2013-09-16 08:49:56 -04:00
|
|
|
module Sidetiq
|
|
|
|
module Lock
|
|
|
|
class Redis
|
|
|
|
include Logging
|
|
|
|
|
|
|
|
attr_reader :key, :timeout
|
|
|
|
|
2013-09-16 12:27:07 -04:00
|
|
|
def self.all
|
|
|
|
Sidekiq.redis do |redis|
|
|
|
|
redis.keys("sidetiq:*:lock").map do |key|
|
|
|
|
new(key)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-09-16 08:49:56 -04:00
|
|
|
def initialize(key, timeout = Sidetiq.config.lock_expire)
|
2013-09-16 12:27:07 -04:00
|
|
|
@key = extract_key(key)
|
2013-09-16 08:49:56 -04:00
|
|
|
@timeout = timeout
|
|
|
|
end
|
|
|
|
|
|
|
|
def synchronize
|
|
|
|
Sidekiq.redis do |redis|
|
2013-09-16 12:27:07 -04:00
|
|
|
acquired = lock
|
2013-09-16 08:49:56 -04:00
|
|
|
|
|
|
|
if acquired
|
2013-09-16 12:27:07 -04:00
|
|
|
debug "Lock: #{key}"
|
2013-09-16 08:49:56 -04:00
|
|
|
|
|
|
|
begin
|
|
|
|
yield redis
|
|
|
|
ensure
|
2013-09-16 12:27:07 -04:00
|
|
|
unlock
|
2013-09-16 08:49:56 -04:00
|
|
|
debug "Unlock: #{key}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-09-17 05:42:07 -04:00
|
|
|
def stale?
|
|
|
|
pttl = meta_data.pttl
|
|
|
|
|
|
|
|
# Consider PTTL of -1 (never set) and larger than the
|
|
|
|
# configured lock_expire as invalid. Locks with timestamps
|
|
|
|
# older than 1 minute are also considered stale.
|
|
|
|
pttl < 0 || pttl >= Sidetiq.config.lock_expire ||
|
|
|
|
meta_data.timestamp < (Sidetiq.clock.gettime.to_i - 60)
|
|
|
|
end
|
|
|
|
|
2013-09-16 12:27:07 -04:00
|
|
|
def meta_data
|
2013-09-17 04:25:55 -04:00
|
|
|
@meta_data ||= Sidekiq.redis do |redis|
|
2013-09-16 12:27:07 -04:00
|
|
|
MetaData.from_json(redis.get(key))
|
|
|
|
end
|
|
|
|
end
|
2013-09-16 08:49:56 -04:00
|
|
|
|
2013-09-16 12:27:07 -04:00
|
|
|
def lock
|
|
|
|
Sidekiq.redis do |redis|
|
|
|
|
acquired = false
|
2013-09-16 08:49:56 -04:00
|
|
|
|
2013-09-16 12:27:07 -04:00
|
|
|
watch(redis, key) do
|
|
|
|
if !redis.exists(key)
|
|
|
|
acquired = !!redis.multi do |multi|
|
|
|
|
meta = MetaData.for_new_lock(key)
|
|
|
|
multi.psetex(key, timeout, meta.to_json)
|
|
|
|
end
|
2013-09-16 08:49:56 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-09-16 12:27:07 -04:00
|
|
|
acquired
|
|
|
|
end
|
2013-09-16 08:49:56 -04:00
|
|
|
end
|
|
|
|
|
2013-09-16 12:27:07 -04:00
|
|
|
def unlock
|
|
|
|
Sidekiq.redis do |redis|
|
|
|
|
watch(redis, key) do
|
|
|
|
if meta_data.owner == Sidetiq::Lock::MetaData::OWNER
|
|
|
|
redis.multi do |multi|
|
|
|
|
multi.del(key)
|
|
|
|
end
|
2013-09-16 12:28:03 -04:00
|
|
|
|
|
|
|
true
|
|
|
|
else
|
|
|
|
false
|
2013-09-16 08:49:56 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-09-16 12:29:47 -04:00
|
|
|
def unlock!
|
|
|
|
Sidekiq.redis do |redis|
|
|
|
|
redis.del(key)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-09-16 12:27:07 -04:00
|
|
|
private
|
|
|
|
|
|
|
|
def extract_key(key)
|
|
|
|
case key
|
|
|
|
when Class
|
|
|
|
"sidetiq:#{key.name}:lock"
|
|
|
|
when String
|
|
|
|
key.match(/sidetiq:(.+):lock/) ? key : "sidetiq:#{key}:lock"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-09-16 08:49:56 -04:00
|
|
|
def watch(redis, *args)
|
|
|
|
redis.watch(*args)
|
|
|
|
|
|
|
|
begin
|
|
|
|
yield
|
|
|
|
ensure
|
|
|
|
redis.unwatch
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|