From 80112fa9430fa3f0fb2b24e690c87d17d475e5e4 Mon Sep 17 00:00:00 2001 From: Alessandro Tagliapietra Date: Fri, 18 Mar 2016 22:22:51 -0700 Subject: [PATCH] Add reset_expire --- lib/redis_mutex.rb | 10 ++++++++++ spec/redis_mutex_spec.rb | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/lib/redis_mutex.rb b/lib/redis_mutex.rb index 31c9526..172ebda 100644 --- a/lib/redis_mutex.rb +++ b/lib/redis_mutex.rb @@ -14,6 +14,7 @@ class RedisMutex < RedisClassy DEFAULT_EXPIRE = 10 LockError = Class.new(StandardError) UnlockError = Class.new(StandardError) + ExpireResetError = Class.new(StandardError) AssertionError = Class.new(StandardError) def initialize(object, options={}) @@ -56,6 +57,15 @@ def try_lock return false # Dammit, it seems that someone else was even faster than us to remove the expired lock! end + # Extends the expire time just in case process needs more time + def reset_expire + raise ExpireResetError, "extend_expire should be called only on locked resources" unless locked? + # we've the lock so we can safely set the new expire time + now = Time.now.to_f + @expires_at = now + @expire + set(@expires_at) + end + # Returns true if resource is locked. Note that nil.to_f returns 0.0 def locked? get.to_f > Time.now.to_f diff --git a/spec/redis_mutex_spec.rb b/spec/redis_mutex_spec.rb index 73b332f..9d231f0 100644 --- a/spec/redis_mutex_spec.rb +++ b/spec/redis_mutex_spec.rb @@ -87,6 +87,27 @@ end end + it 'resets the expire' do + mutex = RedisMutex.new(:test_lock, :expire => 0.5, :block => 0) + expect(mutex.lock).to be_truthy + sleep 0.3 + + mutex.reset_expire + sleep 0.3 # now it shouldn't be expired if reset works + + # someone tries to overwrite the reset expired lock + mutex2 = RedisMutex.new(:test_lock, :expire => 0, :block => 0) + expect(mutex2.lock).to be_falsey + end + + it 'raises ExpireResetError if reset_expire is called when lock mutex is not locked' do + mutex = RedisMutex.new(:test_lock, :expire => 0.1, :block => 0) + expect(mutex.lock).to be_truthy + sleep 0.2 # wait enough to make the lock expired + + expect { mutex.reset_expire {} }.to raise_error(RedisMutex::ExpireResetError) + end + it 'resets locking state on reuse' do mutex = RedisMutex.new(:test_lock, SHORT_MUTEX_OPTIONS) expect(mutex.lock).to be_truthy