module Diplo::Lock
Public Instance Methods
create(resource, ttl = nil)
click to toggle source
# File lib/diplo/lock.rb, line 9 def create(resource, ttl = nil) ttl ||= Env.fetch_int(:lock_ttl) token = create_lock_token lock = OpenStruct.new(resource: resource, token: token) retry_count.times do locked_nodes, start_time = 0, Time.now servers.each do |server| locked_nodes += 1 if lock_server(server, resource, token, ttl) end validity = validity_time(start_time, ttl) if locked_nodes >= quorum && validity > 0 lock.validity = validity return lock else remove lock end delay end false end
create_lock_token()
click to toggle source
# File lib/diplo/lock.rb, line 110 def create_lock_token SecureRandom.hex lock_token_bytes end
delay()
click to toggle source
# File lib/diplo/lock.rb, line 114 def delay sleep rand(retry_delay).to_f / 1000 end
drift_factor()
click to toggle source
# File lib/diplo/lock.rb, line 86 def drift_factor @drift_factor || Env.fetch_float(:lock_drift_factor) end
drift_factor=(factor)
click to toggle source
# File lib/diplo/lock.rb, line 90 def drift_factor=(factor) @drift_factor = Float(factor) end
lock_server(redis, resource, token, ttl)
click to toggle source
# File lib/diplo/lock.rb, line 50 def lock_server(redis, resource, token, ttl) redis.client.call [:set, resource, token, :nx, :px, ttl] rescue false end
lock_token_bytes()
click to toggle source
# File lib/diplo/lock.rb, line 94 def lock_token_bytes @lock_token_bytes || Env.fetch_int(:lock_token_bytes) end
lock_token_bytes=(count)
click to toggle source
# File lib/diplo/lock.rb, line 98 def lock_token_bytes=(count) @lock_token_bytes = Integer(count) end
quorum()
click to toggle source
# File lib/diplo/lock.rb, line 102 def quorum @quorum || Env.fetch_int(:lock_quorum) end
quorum=(nodes)
click to toggle source
# File lib/diplo/lock.rb, line 106 def quorum=(nodes) @quorum = Integer(nodes) end
remove(lock)
click to toggle source
# File lib/diplo/lock.rb, line 36 def remove(lock) servers.each do |server| unlock_server server, lock.resource, lock.token end end
retry_count()
click to toggle source
# File lib/diplo/lock.rb, line 70 def retry_count @retry_count || Env.fetch_int(:lock_retry_count) end
retry_count=(count)
click to toggle source
# File lib/diplo/lock.rb, line 74 def retry_count=(count) @retry_count = Integer(count) end
retry_delay()
click to toggle source
# File lib/diplo/lock.rb, line 78 def retry_delay @retry_delay || Env.fetch_int(:lock_retry_delay) end
retry_delay=(miliseconds)
click to toggle source
# File lib/diplo/lock.rb, line 82 def retry_delay=(miliseconds) @retry_delay = Integer(miliseconds) end
servers()
click to toggle source
# File lib/diplo/lock.rb, line 42 def servers @servers || begin config = Env.fetch(:redis) uris = config.gsub(' ', '').split(',') uris.map { |u| ::Redis.new url: u } end end
unlock_server(redis, resource, token)
click to toggle source
# File lib/diplo/lock.rb, line 56 def unlock_server(redis, resource, token) @unlock_script ||= <<-LUA if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end LUA redis.client.call [:eval, @unlock_script, 1, resource, token] rescue # Nothing to do, unlocking is just a best-effort attempt. end
validity_time(start_time, ttl)
click to toggle source
# File lib/diplo/lock.rb, line 118 def validity_time(start_time, ttl) diff_time = Time.now - start_time drift = (ttl* drift_factor).to_i + 2 ttl - (diff_time * 1000).to_i - drift end