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

42 lines
1.4 KiB
Ruby
Raw Normal View History

2016-03-10 04:41:16 -05:00
module Gitlab
# This class implements an 'exclusive lease'. We call it a 'lease'
# because it has a set expiry time. We call it 'exclusive' because only
# one caller may obtain a lease for a given key at a time. The
# implementation is intended to work across GitLab processes and across
# servers. It is a 'cheap' alternative to using SQL queries and updates:
# you do not need to change the SQL schema to start using
# ExclusiveLease.
2016-03-10 06:37:14 -05:00
#
# It is important to choose the timeout wisely. If the timeout is very
# high (1 hour) then the throughput of your operation gets very low (at
# most once an hour). If the timeout is lower than how long your
# operation may take then you cannot count on exclusivity. For example,
# if the timeout is 10 seconds and you do an operation which may take 20
2016-03-10 06:58:51 -05:00
# seconds then two overlapping operations may hold a lease for the same
# key at the same time.
2016-03-10 06:37:14 -05:00
#
2016-03-10 04:41:16 -05:00
class ExclusiveLease
2016-03-10 06:37:14 -05:00
def initialize(key, timeout:)
2016-03-10 04:41:16 -05:00
@key, @timeout = key, timeout
end
2016-03-10 12:41:57 -05:00
# Try to obtain the lease. Return true on success,
2016-03-10 04:41:16 -05:00
# false if the lease is already taken.
def try_obtain
2016-03-10 12:39:50 -05:00
# Performing a single SET is atomic
2016-03-10 11:05:36 -05:00
!!redis.set(redis_key, '1', nx: true, ex: @timeout)
2016-03-10 04:41:16 -05:00
end
private
def redis
# Maybe someday we want to use a connection pool...
@redis ||= Redis.new(url: Gitlab::RedisConfig.url)
end
def redis_key
"gitlab:exclusive_lease:#{@key}"
end
end
end