class Redlock
Constants
- CLOCK_DRIFT_FACTOR
- DEFAULT_RETRY_COUNT
- DEFAULT_RETRY_DELAY
- UNLOCK_SCRIPT
- VERSION
Public Class Methods
new(*server_urls)
click to toggle source
# File lib/redlock.rb, line 15 def initialize(*server_urls) @servers = [] server_urls.each{|url| @servers << Redis.new(:url => url) } @quorum = server_urls.length / 2 + 1 @retry_count = DEFAULT_RETRY_COUNT @retry_delay = DEFAULT_RETRY_DELAY load_script end
Public Instance Methods
get_unique_lock_id()
click to toggle source
# File lib/redlock.rb, line 57 def get_unique_lock_id val = "" bytes = SecureRandom.random_bytes(20) bytes.each_byte{|b| val << b.to_s(32) } val end
load_script()
click to toggle source
# File lib/redlock.rb, line 26 def load_script @servers.each do |server| @unlock_sha = server.script(:load, UNLOCK_SCRIPT) end end
lock(resource,ttl,val=nil)
click to toggle source
# File lib/redlock.rb, line 66 def lock(resource,ttl,val=nil) val = get_unique_lock_id if val.nil? if @testing_mode == :bypass return { validity: ttl, resource: resource, val: val } elsif @testing_mode == :fail return false end @retry_count.times { n = 0 start_time = (Time.now.to_f*1000).to_i @servers.each{|s| n += 1 if lock_instance(s,resource,val,ttl) } # Add 2 milliseconds to the drift to account for Redis expires # precision, which is 1 milliescond, plus 1 millisecond min drift # for small TTLs. drift = (ttl*CLOCK_DRIFT_FACTOR).to_i + 2 validity_time = ttl-((Time.now.to_f*1000).to_i - start_time)-drift if n >= @quorum && validity_time > 0 return { :validity => validity_time, :resource => resource, :val => val } else @servers.each{|s| unlock_instance(s,resource,val) } end # Wait a random delay before to retry sleep(rand(@retry_delay).to_f/1000) } return false end
lock_instance(redis,resource,val,ttl)
click to toggle source
# File lib/redlock.rb, line 41 def lock_instance(redis,resource,val,ttl) begin return redis.set(resource, val, nx: true, px: ttl) rescue return false end end
set_retry(count,delay)
click to toggle source
# File lib/redlock.rb, line 32 def set_retry(count,delay) @retry_count = count @retry_delay = delay end
testing=(mode)
click to toggle source
# File lib/redlock.rb, line 37 def testing=(mode) @testing_mode = mode end
unlock(lock)
click to toggle source
# File lib/redlock.rb, line 107 def unlock(lock) return if @testing_mode == :bypass @servers.each{|s| unlock_instance(s,lock[:resource],lock[:val]) } end
unlock_instance(redis,resource,val)
click to toggle source
# File lib/redlock.rb, line 49 def unlock_instance(redis,resource,val) begin redis.evalsha(@unlock_sha, keys: [resource], argv: [val]) rescue # Nothing to do, unlocking is just a best-effort attempt. end end