lib/redis/lock.rb in redis-objects-1.4.0 vs lib/redis/lock.rb in redis-objects-1.4.2

- old
+ new

@@ -31,32 +31,32 @@ end # Get the lock and execute the code block. Any other code that needs the lock # (on any server) will spin waiting for the lock up to the :timeout # that was specified when the lock was defined. - def lock(&block) - expiration = nil + def lock + raise ArgumentError, 'Block not given' unless block_given? + expiration = generate_expiration + end_time = nil try_until_timeout do - expiration = generate_expiration - # Use the expiration as the value of the lock. - break if redis.setnx(key, expiration) + end_time = Time.now.to_i + expiration + # Set a NX record and use the Redis expiration mechanism. + # Empty value because the presence of it is enough to lock + # `px` only except an Integer in millisecond + break if redis.set(key, nil, px: expiration, nx: true) - # Lock is being held. Now check to see if it's expired (if we're using - # lock expiration). - # See "Handling Deadlocks" section on http://redis.io/commands/setnx - if !@options[:expiration].nil? + # Backward compatibility code + # TODO: remove at the next major release for performance + unless @options[:expiration].nil? old_expiration = redis.get(key).to_f - if old_expiration < Time.now.to_f - # If it's expired, use GETSET to update it. + # Check it was not an empty string with `zero?` and + # the expiration time is passed. + if !old_expiration.zero? && old_expiration < Time.now.to_f expiration = generate_expiration - old_expiration = redis.getset(key, expiration).to_f - - # Since GETSET returns the old value of the lock, if the old expiration - # is still in the past, we know no one else has expired the locked - # and we now have it. - break if old_expiration < Time.now.to_f + end_time = Time.now.to_i + expiration + break if redis.set(key, nil, px: expiration) end end end begin yield @@ -64,17 +64,18 @@ # We need to be careful when cleaning up the lock key. If we took a really long # time for some reason, and the lock expired, someone else may have it, and # it's not safe for us to remove it. Check how much time has passed since we # wrote the lock key and only delete it if it hasn't expired (or we're not using # lock expiration) - if @options[:expiration].nil? || expiration > Time.now.to_f + if @options[:expiration].nil? || end_time > Time.now.to_f redis.del(key) end end end + # Return expiration in milliseconds def generate_expiration - @options[:expiration].nil? ? 1 : (Time.now + @options[:expiration].to_f + 1).to_f + ((@options[:expiration].nil? ? 1 : @options[:expiration].to_f) * 1000).to_i end private def try_until_timeout