2020-05-24 23:13:21 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module Gitlab
|
|
|
|
module ExclusiveLeaseHelpers
|
|
|
|
# Wrapper around ExclusiveLease that adds retry logic
|
|
|
|
class SleepingLock
|
|
|
|
delegate :cancel, to: :@lease
|
2022-08-27 11:52:29 +05:30
|
|
|
MAX_ATTEMPTS = 65
|
|
|
|
DEFAULT_ATTEMPTS = 10
|
2020-05-24 23:13:21 +05:30
|
|
|
|
|
|
|
def initialize(key, timeout:, delay:)
|
|
|
|
@lease = ::Gitlab::ExclusiveLease.new(key, timeout: timeout)
|
|
|
|
@delay = delay
|
|
|
|
@attempts = 0
|
|
|
|
end
|
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
def obtain(max_attempts = DEFAULT_ATTEMPTS)
|
2020-05-24 23:13:21 +05:30
|
|
|
until held?
|
2022-08-27 11:52:29 +05:30
|
|
|
raise FailedToObtainLockError, 'Failed to obtain a lock' if attempts >= [max_attempts, MAX_ATTEMPTS].min
|
2020-05-24 23:13:21 +05:30
|
|
|
|
|
|
|
sleep(sleep_sec) unless first_attempt?
|
|
|
|
try_obtain
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def retried?
|
|
|
|
attempts > 1
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
attr_reader :delay, :attempts
|
|
|
|
|
|
|
|
def held?
|
|
|
|
@uuid.present?
|
|
|
|
end
|
|
|
|
|
|
|
|
def try_obtain
|
|
|
|
@uuid ||= @lease.try_obtain
|
|
|
|
@attempts += 1
|
|
|
|
end
|
|
|
|
|
|
|
|
def first_attempt?
|
2020-10-24 23:57:45 +05:30
|
|
|
attempts == 0
|
2020-05-24 23:13:21 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
def sleep_sec
|
|
|
|
delay.respond_to?(:call) ? delay.call(attempts) : delay
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|