1
0
Fork 0
mirror of https://github.com/endofunky/sidetiq.git synced 2022-11-09 13:53:30 -05:00

Clean up locking.

This commit is contained in:
Tobias Svensson 2013-09-16 17:27:07 +01:00
parent fb66884f2a
commit 47f67d1ccc
4 changed files with 65 additions and 36 deletions

View file

@ -5,54 +5,79 @@ module Sidetiq
attr_reader :key, :timeout
def self.all
Sidekiq.redis do |redis|
redis.keys("sidetiq:*:lock").map do |key|
new(key)
end
end
end
def initialize(key, timeout = Sidetiq.config.lock_expire)
@key = key.kind_of?(Class) ? "sidetiq:#{key.name}:lock" : "sidetiq:#{key}:lock"
@key = extract_key(key)
@timeout = timeout
end
def synchronize
Sidekiq.redis do |redis|
acquired, meta = lock(redis)
acquired = lock
if acquired
debug "Lock: #{meta}"
debug "Lock: #{key}"
begin
yield redis
ensure
unlock(redis)
unlock
debug "Unlock: #{key}"
end
end
end
end
def meta_data
Sidekiq.redis do |redis|
MetaData.from_json(redis.get(key))
end
end
def lock
Sidekiq.redis do |redis|
acquired = false
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
end
end
acquired
end
end
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
end
end
end
end
private
def lock(redis)
acquired, meta = false, nil
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
end
end
[acquired, meta]
end
def unlock(redis)
watch(redis, key) do
meta = MetaData.from_json(redis.get(key))
if meta.owner == Sidetiq::Lock::MetaData::OWNER
redis.multi do |multi|
multi.del(key)
end
end
def extract_key(key)
case key
when Class
"sidetiq:#{key.name}:lock"
when String
key.match(/sidetiq:(.+):lock/) ? key : "sidetiq:#{key}:lock"
end
end

View file

@ -12,13 +12,7 @@ module Sidetiq
end
app.get "/sidetiq/locks" do
Sidekiq.redis do |redis|
lock_keys = redis.keys('sidetiq:*:lock')
@locks = (lock_keys.any? ? redis.mget(*lock_keys) : []).map do |lock|
Sidetiq::Lock::MetaData.from_json(lock)
end
end
@locks = Sidetiq::Lock::Redis.all.map(&:meta_data)
erb File.read(File.join(VIEWS, 'sidetiq_locks.erb'))
end

View file

@ -21,6 +21,16 @@ class TestLock < Sidetiq::TestCase
end
end
def test_all
Sidekiq.redis do |redis|
redis.set("sidetiq:Foobar:lock", 1)
end
locks = Sidetiq::Lock::Redis.all
assert_equal "sidetiq:Foobar:lock", locks.first.key
end
def test_lock_sets_correct_meta_data
key = SecureRandom.hex(8)
internal_key = "sidetiq:#{key}:lock"

View file

@ -45,7 +45,7 @@ class TestLockMetaData < Sidetiq::TestCase
def test_pttl
lock = Sidetiq::Lock::Redis.new("foobar", 1000000)
md = Sidekiq.redis do |r|
lock.send(:lock, r)
lock.lock
Sidetiq::Lock::MetaData.from_json(r.get(lock.key))
end