Class: Redlock::Client
- Inherits:
-
Object
- Object
- Redlock::Client
- Defined in:
- lib/redlock/client.rb,
lib/redlock/testing.rb
Defined Under Namespace
Classes: RedisInstance
Constant Summary collapse
- DEFAULT_REDIS_URLS =
['redis://localhost:6379']
- DEFAULT_REDIS_TIMEOUT =
0.1
- DEFAULT_RETRY_COUNT =
3
- DEFAULT_RETRY_DELAY =
200
- DEFAULT_RETRY_JITTER =
50
- CLOCK_DRIFT_FACTOR =
0.01
Instance Attribute Summary collapse
-
#testing_mode ⇒ Object
writeonly
Sets the attribute testing_mode.
Instance Method Summary collapse
-
#initialize(servers = DEFAULT_REDIS_URLS, options = {}) ⇒ Client
constructor
Create a distributed lock manager implementing redlock algorithm.
-
#lock(resource, ttl, options = {}, &block) ⇒ Object
Locks a resource for a given time.
-
#lock!(*args) ⇒ Object
Locks a resource, executing the received block only after successfully acquiring the lock, and returning its return value as a result.
- #try_lock_instances(resource, ttl, options) ⇒ Object
- #try_lock_instances_without_testing ⇒ Object
-
#unlock(lock_info) ⇒ Object
Unlocks a resource.
-
#unlock_without_testing ⇒ Object
Unlocks a resource.
Constructor Details
#initialize(servers = DEFAULT_REDIS_URLS, options = {}) ⇒ Client
Create a distributed lock manager implementing redlock algorithm. Params:
servers
-
The array of redis connection URLs or Redis connection instances. Or a mix of both.
options
-
You can override the default value for ‘retry_count`, `retry_delay` and `retry_gitter`.
* `retry_count` being how many times it'll try to lock a resource (default: 3)
* `retry_delay` being how many ms to sleep before try to lock again (default: 200)
* `retry_jitter` being how many ms to jitter retry delay (default: 50)
* `redis_timeout` being how the Redis timeout will be set in seconds (default: 0.1)
21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/redlock/client.rb', line 21 def initialize(servers = DEFAULT_REDIS_URLS, = {}) redis_timeout = [:redis_timeout] || DEFAULT_REDIS_TIMEOUT @servers = servers.map do |server| if server.is_a?(String) RedisInstance.new(url: server, timeout: redis_timeout) else RedisInstance.new(server) end end @quorum = servers.length / 2 + 1 @retry_count = [:retry_count] || DEFAULT_RETRY_COUNT @retry_delay = [:retry_delay] || DEFAULT_RETRY_DELAY @retry_jitter = [:retry_jitter] || DEFAULT_RETRY_JITTER end |
Instance Attribute Details
#testing_mode=(value) ⇒ Object (writeonly)
Sets the attribute testing_mode
3 4 5 |
# File 'lib/redlock/testing.rb', line 3 def testing_mode=(value) @testing_mode = value end |
Instance Method Details
#lock(resource, ttl, options = {}, &block) ⇒ Object
Locks a resource for a given time. Params:
resource
-
the resource (or key) string to be locked.
ttl
-
The time-to-live in ms for the lock.
options
-
Hash of optional parameters
* +extend+: A lock ("lock_info") to extend.
* +extend_only_if_life+: If +extend+ is given, only acquire lock if currently held
block
-
an optional block to be executed; after its execution, the lock (if successfully
acquired) is automatically unlocked.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/redlock/client.rb', line 45 def lock(resource, ttl, = {}, &block) lock_info = try_lock_instances(resource, ttl, ) if block_given? begin yield lock_info !!lock_info ensure unlock(lock_info) if lock_info end else lock_info end end |
#lock!(*args) ⇒ Object
Locks a resource, executing the received block only after successfully acquiring the lock, and returning its return value as a result. See Redlock::Client#lock for parameters.
70 71 72 73 74 75 76 77 |
# File 'lib/redlock/client.rb', line 70 def lock!(*args) fail 'No block passed' unless block_given? lock(*args) do |lock_info| raise LockError, 'failed to acquire lock' unless lock_info return yield end end |
#try_lock_instances(resource, ttl, options) ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/redlock/client.rb', line 149 def try_lock_instances(resource, ttl, ) tries = [:extend] ? 1 : @retry_count tries.times do |attempt_number| # Wait a random delay before retrying. sleep((@retry_delay + rand(@retry_jitter)).to_f / 1000) if attempt_number > 0 lock_info = lock_instances(resource, ttl, ) return lock_info if lock_info end false end |
#try_lock_instances_without_testing ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 |
# File 'lib/redlock/testing.rb', line 5 def try_lock_instances(resource, ttl, ) tries = [:extend] ? 1 : @retry_count tries.times do |attempt_number| # Wait a random delay before retrying. sleep((@retry_delay + rand(@retry_jitter)).to_f / 1000) if attempt_number > 0 lock_info = lock_instances(resource, ttl, ) return lock_info if lock_info end false end |
#unlock(lock_info) ⇒ Object
Unlocks a resource. Params:
lock_info
-
the lock that has been acquired when you locked the resource.
63 64 65 |
# File 'lib/redlock/client.rb', line 63 def unlock(lock_info) @servers.each { |s| s.unlock(lock_info[:resource], lock_info[:value]) } end |
#unlock_without_testing ⇒ Object
Unlocks a resource. Params:
lock_info
-
the lock that has been acquired when you locked the resource.
21 22 23 |
# File 'lib/redlock/testing.rb', line 21 def unlock(lock_info) @servers.each { |s| s.unlock(lock_info[:resource], lock_info[:value]) } end |