Class: MasterLock::RedisLock

Inherits:
Object
  • Object
show all
Defined in:
lib/master_lock/redis_lock.rb

Overview

RedisLock implements a mutex in Redis according to the strategy documented at redis.io/commands/SET#patterns. The lock has a string identifier and when acquired will be registered to an owner, also identified by a string. Locks have an expiration time, after which they will be released automatically so that unexpected failures do not result in locks getting stuck.

Constant Summary collapse

DEFAULT_SLEEP_INTERVAL =
0.1

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(redis:, key:, owner:, ttl:, sleep_interval: DEFAULT_SLEEP_INTERVAL) ⇒ RedisLock



25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/master_lock/redis_lock.rb', line 25

def initialize(
  redis:,
  key:,
  owner:,
  ttl:,
  sleep_interval: DEFAULT_SLEEP_INTERVAL
)
  @redis = redis
  @key = key
  @owner = owner
  @ttl = ttl
  @sleep_interval = sleep_interval
end

Instance Attribute Details

#keyString (readonly)



17
18
19
# File 'lib/master_lock/redis_lock.rb', line 17

def key
  @key
end

#ownerString (readonly)



20
21
22
# File 'lib/master_lock/redis_lock.rb', line 20

def owner
  @owner
end

#redisRedis (readonly)



14
15
16
# File 'lib/master_lock/redis_lock.rb', line 14

def redis
  @redis
end

#ttlFixnum (readonly)



23
24
25
# File 'lib/master_lock/redis_lock.rb', line 23

def ttl
  @ttl
end

Instance Method Details

#acquire(timeout:) ⇒ Boolean

Attempt to acquire the lock. If the lock is already held, this will attempt multiple times to acquire the lock until the timeout period is up.



44
45
46
47
48
49
50
51
52
# File 'lib/master_lock/redis_lock.rb', line 44

def acquire(timeout:)
  timeout_time = Time.now + timeout
  loop do
    locked = redis.set(redis_key, owner, nx: true, px: ttl_ms)
    return true if locked
    return false if Time.now >= timeout_time
    sleep(@sleep_interval)
  end
end

#extendBoolean

Extend the expiration time of the lock if still held by this owner. If the lock is no longer held by the owner, this method will fail and return false. The lock lifetime is extended by the configured ttl.



59
60
61
62
63
64
65
66
67
# File 'lib/master_lock/redis_lock.rb', line 59

def extend
  result = eval_script(
    RedisScripts::EXTEND_SCRIPT,
    RedisScripts::EXTEND_SCRIPT_HASH,
    keys: [redis_key],
    argv: [owner, ttl_ms]
  )
  result != 0
end

#releaseBoolean

Release the lock if still held by this owner. If the lock is no longer held by the owner, this method will fail and return false.



73
74
75
76
77
78
79
80
81
# File 'lib/master_lock/redis_lock.rb', line 73

def release
  result = eval_script(
    RedisScripts::RELEASE_SCRIPT,
    RedisScripts::RELEASE_SCRIPT_HASH,
    keys: [redis_key],
    argv: [owner]
  )
  result != 0
end