class Sqeduler::RedisLock
Uses eval_sha to execute server-side scripts on redis. Avoids some of the potentially racey and brittle dependencies on Time-based redis locks in other locking libraries.
Constants
- SLEEP_TIME
Attributes
key[R]
timeout[R]
Public Class Methods
new(key, options = {})
click to toggle source
# File lib/sqeduler/redis_lock.rb, line 13 def initialize(key, options = {}) @key = key @expiration = options[:expiration] raise ArgumentError, "Expiration must be provided!" unless @expiration @timeout = options[:timeout] || 5 end
with_lock(key, options) { || ... }
click to toggle source
# File lib/sqeduler/redis_lock.rb, line 66 def self.with_lock(key, options) raise "Block is required" unless block_given? mutex = new(key, options) unless mutex.lock raise LockTimeoutError, "Timed out trying to get #{key} lock. Exceeded #{mutex.timeout} sec" end begin yield ensure mutex.unlock end end
Public Instance Methods
expiration_milliseconds()
click to toggle source
# File lib/sqeduler/redis_lock.rb, line 79 def expiration_milliseconds # expiration needs to be an integer @expiration ? (@expiration * 1000).to_i : 0 end
lock()
click to toggle source
# File lib/sqeduler/redis_lock.rb, line 20 def lock Service.logger.info( "Try to acquire lock with #{key}, expiration: #{@expiration} sec, timeout: #{timeout} sec" ) return true if locked? if poll_for_lock Service.logger.info "Acquired lock #{key} with value #{lock_value}" true else Service.logger.info "Failed to acquire lock #{key} with value #{lock_value}" false end end
locked?()
click to toggle source
# File lib/sqeduler/redis_lock.rb, line 54 def locked? redis_pool.with do |redis| if redis.get(key) == lock_value Service.logger.info "Lock #{key} with value #{lock_value} is valid" true else Service.logger.info "Lock #{key} with value #{lock_value} has expired or is not present" false end end end
refresh()
click to toggle source
# File lib/sqeduler/redis_lock.rb, line 44 def refresh if refresh_lock Service.logger.info "Refreshed lock #{key} with value #{lock_value}" true else Service.logger.info "Cannot refresh lock #{key} with value #{lock_value}" false end end
unlock()
click to toggle source
# File lib/sqeduler/redis_lock.rb, line 34 def unlock if release_lock Service.logger.info "Released lock #{key} with value #{lock_value}" true else Service.logger.info "Cannot release lock #{key} with value #{lock_value}" false end end
Private Instance Methods
lock_value()
click to toggle source
# File lib/sqeduler/redis_lock.rb, line 86 def lock_value @lock_value ||= LockValue.new.value end
poll_for_lock()
click to toggle source
# File lib/sqeduler/redis_lock.rb, line 90 def poll_for_lock start = Time.now ran_at_least_once = false while Time.now - start < timeout || !ran_at_least_once locked = take_lock break if locked ran_at_least_once = true sleep SLEEP_TIME end locked end
redis_pool()
click to toggle source
# File lib/sqeduler/redis_lock.rb, line 108 def redis_pool Service.redis_pool end
take_lock()
click to toggle source
# File lib/sqeduler/redis_lock.rb, line 102 def take_lock redis_pool.with do |redis| redis.set(key, lock_value, :nx => true, :px => expiration_milliseconds) end end