debian-mirror-gitlab/lib/gitlab/exclusive_lease.rb

53 lines
1.5 KiB
Ruby
Raw Normal View History

2017-08-17 22:00:37 +05:30
require 'securerandom'
2016-04-02 18:10:28 +05:30
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
2017-08-17 22:00:37 +05:30
# servers. It is a cheap alternative to using SQL queries and updates:
2016-04-02 18:10:28 +05:30
# you do not need to change the SQL schema to start using
# ExclusiveLease.
#
class ExclusiveLease
2017-08-17 22:00:37 +05:30
LUA_CANCEL_SCRIPT = <<-EOS.freeze
local key, uuid = KEYS[1], ARGV[1]
if redis.call("get", key) == uuid then
redis.call("del", key)
end
EOS
def self.cancel(key, uuid)
Gitlab::Redis.with do |redis|
redis.eval(LUA_CANCEL_SCRIPT, keys: [redis_key(key)], argv: [uuid])
end
end
def self.redis_key(key)
"gitlab:exclusive_lease:#{key}"
end
2016-04-02 18:10:28 +05:30
def initialize(key, timeout:)
2017-08-17 22:00:37 +05:30
@redis_key = self.class.redis_key(key)
@timeout = timeout
@uuid = SecureRandom.uuid
2016-04-02 18:10:28 +05:30
end
2017-08-17 22:00:37 +05:30
# Try to obtain the lease. Return lease UUID on success,
2016-04-02 18:10:28 +05:30
# false if the lease is already taken.
def try_obtain
# Performing a single SET is atomic
2016-06-02 11:05:42 +05:30
Gitlab::Redis.with do |redis|
2017-08-17 22:00:37 +05:30
redis.set(@redis_key, @uuid, nx: true, ex: @timeout) && @uuid
2016-06-02 11:05:42 +05:30
end
2016-04-02 18:10:28 +05:30
end
2016-11-03 12:29:30 +05:30
# Returns true if the key for this lease is set.
def exists?
Gitlab::Redis.with do |redis|
2017-08-17 22:00:37 +05:30
redis.exists(@redis_key)
2016-11-03 12:29:30 +05:30
end
end
2016-04-02 18:10:28 +05:30
end
end