Class: RedisLocks::Mutex
- Inherits:
-
Object
- Object
- RedisLocks::Mutex
- Defined in:
- lib/redis_locks/mutex.rb
Constant Summary collapse
- NAMESPACE =
"mutex"
Instance Method Summary collapse
- #expired?(safety_margin: 0) ⇒ Boolean
-
#initialize(key, expires_in: 86400, redis: RedisLocks.redis) ⇒ Mutex
constructor
A new instance of Mutex.
- #lock(expires_at: nil, &block) ⇒ Object
- #lock!(expires_at: nil, &block) ⇒ Object
- #not_expired!(safety_margin: 0) ⇒ Object
- #unlock ⇒ Object
Constructor Details
#initialize(key, expires_in: 86400, redis: RedisLocks.redis) ⇒ Mutex
Returns a new instance of Mutex.
18 19 20 21 22 23 24 |
# File 'lib/redis_locks/mutex.rb', line 18 def initialize(key, expires_in: 86400, redis: RedisLocks.redis) @key = "#{NAMESPACE}:#{key}" @redis = Connections.ensure_pool(redis) @expires_in = expires_in.to_i raise ArgumentError.new("Invalid expires_in: #{expires_in}") unless expires_in > 0 end |
Instance Method Details
#expired?(safety_margin: 0) ⇒ Boolean
75 76 77 78 79 |
# File 'lib/redis_locks/mutex.rb', line 75 def expired?(safety_margin: 0) return true unless @expires_at Time.now.utc.to_i + safety_margin >= @expires_at end |
#lock(expires_at: nil, &block) ⇒ Object
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/redis_locks/mutex.rb', line 26 def lock(expires_at: nil, &block) now = Time.now.utc.to_i locked = false if expires_at expires_at = expires_at.to_i else expires_at = now + @expires_in end @redis.with do |conn| if conn.setnx(@key, expires_at) conn.expire(@key, expires_at - now) @expires_at = expires_at locked = true else # it was locked if (old_value = conn.get(@key)).to_i <= now # lock has expired if conn.getset(@key, expires_at) == old_value @expires_at = expires_at locked = true end end end end return false unless locked return_or_yield(&block) end |
#lock!(expires_at: nil, &block) ⇒ Object
57 58 59 60 61 |
# File 'lib/redis_locks/mutex.rb', line 57 def lock!(expires_at: nil, &block) locked = lock(expires_at: expires_at) raise AlreadyLocked.new(@key) unless locked return_or_yield(&block) end |
#not_expired!(safety_margin: 0) ⇒ Object
81 82 83 |
# File 'lib/redis_locks/mutex.rb', line 81 def not_expired!(safety_margin: 0) raise MutexExpired.new(@key) if expired?(safety_margin: safety_margin) end |
#unlock ⇒ Object
63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/redis_locks/mutex.rb', line 63 def unlock return unless @expires_at # To prevent deleting a lock acquired from another process, only delete # the key if it's still valid, and will be for another 2 seconds if !expired?(safety_margin: 2) @redis.with { |conn| conn.del(@key) } end @expires_at = nil end |