class Ribbon::Intercom::Service::Channel::Stores::RedisStore::Mutex
A redis mutex inspired by <github.com/leandromoreira/redlock-rb>
Constants
- CLOCK_DRIFT_FACTOR
- DEFAULT_RETRY_COUNT
- DEFAULT_RETRY_DELAY
- UNLOCK_SCRIPT
Lua script to send to Redis when releasing a lock. See: redis.io/commands/set
Attributes
name[R]
redis[R]
retry_count[R]
retry_delay[R]
Public Class Methods
new(redis, name, opts={})
click to toggle source
# File lib/ribbon/intercom/service/channel/stores/redis_store.rb, line 136 def initialize(redis, name, opts={}) @redis = redis @name = name @retry_count = opts[:retry_count] || DEFAULT_RETRY_COUNT @retry_delay = opts[:retry_delay] || DEFAULT_RETRY_DELAY end
time_in_ms()
click to toggle source
# File lib/ribbon/intercom/service/channel/stores/redis_store.rb, line 126 def time_in_ms (Time.now.to_f * 1000).to_i end
Public Instance Methods
lock(ttl=1000)
click to toggle source
Acquire a lock (non-blocking).
# File lib/ribbon/intercom/service/channel/stores/redis_store.rb, line 164 def lock(ttl=1000) handle = SecureRandom.uuid redis.set(name, handle, nx: true, px: ttl) && handle end
synchronize(ttl) { |ttl| ... }
click to toggle source
# File lib/ribbon/intercom/service/channel/stores/redis_store.rb, line 143 def synchronize(ttl) retry_count.times { start_time = self.class.time_in_ms if (handle=lock(ttl)) begin time_elapsed = (self.class.time_in_ms - start_time).to_i return yield(ttl - time_elapsed - _drift(ttl)) ensure unlock(handle) end else sleep(rand(retry_delay).to_f / 1000) end } raise LockUnobtainableError, name end
unlock(handle)
click to toggle source
Release a lock.
# File lib/ribbon/intercom/service/channel/stores/redis_store.rb, line 171 def unlock(handle) redis.eval(UNLOCK_SCRIPT, [name], [handle]) rescue # Do nothing, unlocking is best effort. end
Private Instance Methods
_drift(ttl)
click to toggle source
Approximate clock drift.
# File lib/ribbon/intercom/service/channel/stores/redis_store.rb, line 181 def _drift(ttl) # Add 2 milliseconds to the drift to account for Redis expires # precision, which is 1 millisecond, plus 1 millisecond min drift # for small TTLs. (ttl * CLOCK_DRIFT_FACTOR).to_i + 2 end