# frozen_string_literal: true

module UpdateHighestRole
  extend ActiveSupport::Concern

  HIGHEST_ROLE_LEASE_TIMEOUT = 10.minutes.to_i
  HIGHEST_ROLE_JOB_DELAY = 10.minutes

  included do
    after_commit :update_highest_role
  end

  private

  # Schedule a Sidekiq job to update the highest role for a User
  #
  # The job will be called outside of a transaction in order to ensure the changes
  # to be commited before attempting to update the highest role.
  # The exlusive lease will not be released after completion to prevent multiple jobs
  # being executed during the defined timeout.
  def update_highest_role
    return unless update_highest_role?

    run_after_commit_or_now do
      lease_key = "update_highest_role:#{update_highest_role_attribute}"
      lease = Gitlab::ExclusiveLease.new(lease_key, timeout: HIGHEST_ROLE_LEASE_TIMEOUT)

      if lease.try_obtain
        UpdateHighestRoleWorker.perform_in(HIGHEST_ROLE_JOB_DELAY, update_highest_role_attribute)
      else
        # use same logging as ExclusiveLeaseGuard
        Gitlab::AppLogger.error('Cannot obtain an exclusive lease. There must be another instance already in execution.')
      end
    end
  end
end
