2018-10-22 03:00:50 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2018-07-03 03:20:27 -04:00
|
|
|
module Gitlab
|
|
|
|
# This module provides helper methods which are intregrated with GitLab::ExclusiveLease
|
|
|
|
module ExclusiveLeaseHelpers
|
|
|
|
FailedToObtainLockError = Class.new(StandardError)
|
|
|
|
|
|
|
|
##
|
2020-05-06 02:09:36 -04:00
|
|
|
# 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.
|
2018-07-03 03:20:27 -04:00
|
|
|
#
|
2020-05-06 02:09:36 -04:00
|
|
|
# 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.
|
2018-07-03 03:20:27 -04:00
|
|
|
# This could potentially eat up all connection pools.
|
|
|
|
def in_lock(key, ttl: 1.minute, retries: 10, sleep_sec: 0.01.seconds)
|
2018-11-23 11:25:11 -05:00
|
|
|
raise ArgumentError, 'Key needs to be specified' unless key
|
|
|
|
|
2020-05-06 02:09:36 -04:00
|
|
|
lease = SleepingLock.new(key, timeout: ttl, delay: sleep_sec)
|
2018-07-03 03:20:27 -04:00
|
|
|
|
2020-05-06 02:09:36 -04:00
|
|
|
lease.obtain(1 + retries)
|
2018-07-03 03:20:27 -04:00
|
|
|
|
2020-05-06 02:09:36 -04:00
|
|
|
yield(lease.retried?)
|
2018-07-03 03:20:27 -04:00
|
|
|
ensure
|
2020-05-06 02:09:36 -04:00
|
|
|
lease&.cancel
|
2018-07-03 03:20:27 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|