class RedisGetlock
Constants
- EXPIRE
- INTERVAL
- TIMEOUT
- VERSION
Attributes
expire[R]
interval[R]
key[R]
logger[R]
redis[R]
timeout[R]
uuid[R]
Public Class Methods
new(redis:, key:, logger: nil, timeout: TIMEOUT, expire: EXPIRE, interval: INTERVAL)
click to toggle source
# File lib/redis_getlock.rb, line 15 def initialize(redis:, key:, logger: nil, timeout: TIMEOUT, expire: EXPIRE, interval: INTERVAL) @redis = redis @key = key @logger = logger @timeout = timeout @expire = expire @interval = interval @uuid = SecureRandom.uuid end
Public Instance Methods
lock()
click to toggle source
# File lib/redis_getlock.rb, line 25 def lock logger.info { "#{log_head}Wait #{timeout < 0 ? '' : "#{timeout} sec "}to acquire a redis lock '#{key}'" } if logger if set_options_available? locked = lock_with_set_options else locked = lock_without_set_options end @thr.terminate if @thr and @thr.alive? if locked @thr = Thread.new(&method(:keeplock)) logger.info { "#{log_head}Acquired a redis lock '#{key}'" } if logger true else logger.info { "#{log_head}Timeout to acquire a redis lock '#{key}'" } if logger false end end
locked?()
click to toggle source
# File lib/redis_getlock.rb, line 75 def locked? redis.exists(key) end
self_locked?()
click to toggle source
# File lib/redis_getlock.rb, line 79 def self_locked? locked? && uuid == JSON.parse(redis.get(key))['uuid'] end
synchronize() { || ... }
click to toggle source
# File lib/redis_getlock.rb, line 83 def synchronize(&block) raise LockError unless lock begin yield ensure unlock end end
try_lock()
click to toggle source
# File lib/redis_getlock.rb, line 43 def try_lock if set_options_available? locked = try_lock_with_set_options else locked = try_lock_without_set_options end @thr.terminate if @thr and @thr.alive? if locked @thr = Thread.new(&method(:keeplock)) logger.info { "#{log_head}Acquired a redis lock '#{key}'" } if logger true else logger.info { "#{log_head}A redis lock is already acquired '#{key}'" } if logger false end end
unlock()
click to toggle source
# File lib/redis_getlock.rb, line 60 def unlock @thr.terminate if @thr and @thr.alive? if self_locked? redis.del(key) logger.info { "#{log_head}Released a redis lock '#{key}'" } if logger true elsif locked? logger.info { "#{log_head}Failed to release a redis lock since somebody else locked '#{key}'" } if logger false else logger.info { "#{log_head}Redis lock did not exist '#{key}'" } if logger true end end
Private Instance Methods
keeplock()
click to toggle source
# File lib/redis_getlock.rb, line 156 def keeplock loop do current = Time.now.to_f payload = {uuid: uuid, expire_at: (current + expire).to_s}.to_json redis.setex(key, expire, payload) # extend expiration sleep interval end end
lock_with_set_options()
click to toggle source
redis >= 2.6.12 ref. redis.io/commands/set
# File lib/redis_getlock.rb, line 106 def lock_with_set_options started = Time.now.to_f loop do locked = try_lock_with_set_options return true if locked break if timeout >= 0 and (Time.now.to_f - started) >= timeout sleep interval end false end
lock_without_set_options()
click to toggle source
redis < 2.6.12 ref. redis.io/commands/setnx
# File lib/redis_getlock.rb, line 119 def lock_without_set_options started = Time.now.to_f loop do locked = try_lock_without_set_options return true if locked break if timeout >= 0 and (Time.now.to_f - started) >= timeout sleep interval end false end
log_head()
click to toggle source
# File lib/redis_getlock.rb, line 94 def log_head "PID-#{::Process.pid} TID-#{::Thread.current.object_id.to_s(36)}: " end
set_options_available?()
click to toggle source
# File lib/redis_getlock.rb, line 98 def set_options_available? return @set_options_avialble unless @set_options_avialble.nil? major, minor, patch = redis.info['redis_version'].split('.').map(&:to_i) @set_options_avialble = major > 2 || (major == 2 && minor > 7) || (major == 2 && minor == 6 && patch >= 12) end
try_lock_with_set_options()
click to toggle source
redis >= 2.6.12 ref. redis.io/commands/set
# File lib/redis_getlock.rb, line 132 def try_lock_with_set_options current = Time.now.to_f payload = {uuid: uuid, expire_at: (current + expire).to_s}.to_json return true if redis.set(key, payload, {nx: true, ex: expire}) # key does not exist false end
try_lock_without_set_options()
click to toggle source
redis < 2.6.12 ref. redis.io/commands/setnx
# File lib/redis_getlock.rb, line 141 def try_lock_without_set_options current = Time.now.to_f payload = {uuid: uuid, expire_at: (current + expire).to_s}.to_json if redis.setnx(key, payload) # key does not exist redis.expire(key, expire) return true # acquire lock end previous = JSON.parse(redis.get(key)) if previous['expire_at'].to_f < current # key exists, but previous compared = redis.getset(key, paylod) return true if previous['expire_at'] == compared['expire_at'] # acquire lock end false end