Class: Ribbon::Intercom::Service::Channel::Stores::RedisStore::Mutex
- Inherits:
-
Object
- Object
- Ribbon::Intercom::Service::Channel::Stores::RedisStore::Mutex
- Defined in:
- lib/ribbon/intercom/service/channel/stores/redis_store.rb
Overview
A redis mutex inspired by <github.com/leandromoreira/redlock-rb>
Defined Under Namespace
Classes: LockUnobtainableError
Constant Summary collapse
- UNLOCK_SCRIPT =
Lua script to send to Redis when releasing a lock. See: redis.io/commands/set
<<-LUA if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end LUA
- DEFAULT_RETRY_COUNT =
3
- DEFAULT_RETRY_DELAY =
200
- CLOCK_DRIFT_FACTOR =
0.01
Instance Attribute Summary collapse
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#redis ⇒ Object
readonly
Class Methods.
-
#retry_count ⇒ Object
readonly
Returns the value of attribute retry_count.
-
#retry_delay ⇒ Object
readonly
Returns the value of attribute retry_delay.
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(redis, name, opts = {}) ⇒ Mutex
constructor
A new instance of Mutex.
-
#lock(ttl = 1000) ⇒ Object
Acquire a lock (non-blocking).
- #synchronize(ttl) ⇒ Object
-
#unlock(handle) ⇒ Object
Release a lock.
Constructor Details
#initialize(redis, name, opts = {}) ⇒ Mutex
Returns a new instance of Mutex.
136 137 138 139 140 141 |
# 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 |
Instance Attribute Details
#name ⇒ Object (readonly)
Returns the value of attribute name.
132 133 134 |
# File 'lib/ribbon/intercom/service/channel/stores/redis_store.rb', line 132 def name @name end |
#redis ⇒ Object (readonly)
Class Methods
131 132 133 |
# File 'lib/ribbon/intercom/service/channel/stores/redis_store.rb', line 131 def redis @redis end |
#retry_count ⇒ Object (readonly)
Returns the value of attribute retry_count.
133 134 135 |
# File 'lib/ribbon/intercom/service/channel/stores/redis_store.rb', line 133 def retry_count @retry_count end |
#retry_delay ⇒ Object (readonly)
Returns the value of attribute retry_delay.
134 135 136 |
# File 'lib/ribbon/intercom/service/channel/stores/redis_store.rb', line 134 def retry_delay @retry_delay end |
Class Method Details
.time_in_ms ⇒ Object
126 127 128 |
# File 'lib/ribbon/intercom/service/channel/stores/redis_store.rb', line 126 def time_in_ms (Time.now.to_f * 1000).to_i end |
Instance Method Details
#lock(ttl = 1000) ⇒ Object
Acquire a lock (non-blocking).
164 165 166 167 |
# 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) ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# 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) ⇒ Object
Release a lock.
171 172 173 174 175 |
# 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 |