diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-06 09:09:36 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-06 09:09:36 +0300 |
commit | 0c4b9cacd575b3e71e41a13f042062b3adcb4caf (patch) | |
tree | fd06e55f276c1fa42327a41860e328b46a8cb8ee /lib/gitlab/exclusive_lease_helpers.rb | |
parent | 6c005ae9783ad6752e3082d05e1053d20d8da92a (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'lib/gitlab/exclusive_lease_helpers.rb')
-rw-r--r-- | lib/gitlab/exclusive_lease_helpers.rb | 43 |
1 files changed, 24 insertions, 19 deletions
diff --git a/lib/gitlab/exclusive_lease_helpers.rb b/lib/gitlab/exclusive_lease_helpers.rb index a1504833039..10762d83588 100644 --- a/lib/gitlab/exclusive_lease_helpers.rb +++ b/lib/gitlab/exclusive_lease_helpers.rb @@ -6,33 +6,38 @@ module Gitlab FailedToObtainLockError = Class.new(StandardError) ## - # This helper method blocks a process/thread until the other process cancel the obrainted lease key. + # This helper method blocks a process/thread until the lease can be acquired, either due to + # the lease TTL expiring, or due to the current holder explicitly releasing + # their hold. # - # Note: It's basically discouraged to use this method in the unicorn's thread, - # because it holds the connection until all `retries` is consumed. + # If the lease cannot be obtained, raises `FailedToObtainLockError`. + # + # @param [String] key The lock the thread will try to acquire. Only one thread + # in one process across all Rails instances can hold this named lock at any + # one time. + # @param [Float] ttl: The length of time the lock will be valid for. The lock + # will be automatically be released after this time, so any work should be + # completed within this time. + # @param [Integer] retries: The maximum number of times we will re-attempt + # to acquire the lock. The maximum number of attempts will be `retries + 1`: + # one for the initial attempt, and then one for every re-try. + # @param [Float|Proc] sleep_sec: Either a number of seconds to sleep, or + # a proc that computes the sleep time given the number of preceding attempts + # (from 1 to retries - 1) + # + # Note: It's basically discouraged to use this method in a unicorn thread, + # because this ties up all thread related resources until all `retries` are consumed. # This could potentially eat up all connection pools. def in_lock(key, ttl: 1.minute, retries: 10, sleep_sec: 0.01.seconds) raise ArgumentError, 'Key needs to be specified' unless key - lease = Gitlab::ExclusiveLease.new(key, timeout: ttl) - retried = false - max_attempts = 1 + retries - - until uuid = lease.try_obtain - # Keep trying until we obtain the lease. To prevent hammering Redis too - # much we'll wait for a bit. - attempt_number = max_attempts - retries - delay = sleep_sec.respond_to?(:call) ? sleep_sec.call(attempt_number) : sleep_sec - - sleep(delay) - (retries -= 1) < 0 ? break : retried ||= true - end + lease = SleepingLock.new(key, timeout: ttl, delay: sleep_sec) - raise FailedToObtainLockError, 'Failed to obtain a lock' unless uuid + lease.obtain(1 + retries) - yield(retried) + yield(lease.retried?) ensure - Gitlab::ExclusiveLease.cancel(key, uuid) + lease&.cancel end end end |