Class: RedisLocks::Mutex

Inherits:
Object
  • Object
show all
Defined in:
lib/redis_locks/mutex.rb

Constant Summary collapse

NAMESPACE =
"mutex"

Instance Method Summary collapse

Constructor Details

#initialize(key, expires_in: 86400, redis: RedisLocks.redis) ⇒ Mutex

Returns a new instance of Mutex.

Raises:

  • (ArgumentError)


12
13
14
15
16
17
18
# File 'lib/redis_locks/mutex.rb', line 12

def initialize(key, expires_in: 86400, redis: RedisLocks.redis)
  @key = "#{NAMESPACE}:#{key}"
  @redis = redis
  @expires_in = expires_in.to_i

  raise ArgumentError.new("Invalid expires_in: #{expires_in}") unless expires_in > 0
end

Instance Method Details

#lock(expires_at: nil, &block) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/redis_locks/mutex.rb', line 20

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

  if @redis.setnx(@key, expires_at)
    @redis.expire(@key, expires_at - now)
    @expires_at = expires_at
    locked = true
  else # it was locked
    if (old_value = @redis.get(@key)).to_i <= now
      # lock has expired
      if @redis.getset(@key, expires_at) == old_value
        @expires_at = expires_at
        locked = true
      end
    end
  end

  return false unless locked

  return_or_yield(&block)
end

#lock!(expires_at: nil, &block) ⇒ Object

Raises:



49
50
51
52
53
# File 'lib/redis_locks/mutex.rb', line 49

def lock!(expires_at: nil, &block)
  locked = lock(expires_at: expires_at)
  raise AlreadyLocked.new(@key) unless locked
  return_or_yield(&block)
end

#unlockObject



55
56
57
58
59
60
61
62
63
64
65
# File 'lib/redis_locks/mutex.rb', line 55

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 Time.now.utc.to_i - 2 < @expires_at
    @redis.del(@key)
  end

  @expires_at = nil
end