gitlab-org--gitlab-foss/lib/gitlab/exclusive_lease_helpers.rb

44 lines
2.0 KiB
Ruby

# frozen_string_literal: true
module Gitlab
# This module provides helper methods which are intregrated with GitLab::ExclusiveLease
module ExclusiveLeaseHelpers
FailedToObtainLockError = Class.new(StandardError)
##
# 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.
#
# 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 webserver 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 = SleepingLock.new(key, timeout: ttl, delay: sleep_sec)
lease.obtain(1 + retries)
yield(lease.retried?, lease)
ensure
lease&.cancel
end
end
end