redis_queued_locks 1.12.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +42 -5
- data/LICENSE.txt +1 -1
- data/README.md +231 -203
- data/Rakefile +12 -4
- data/Steepfile +16 -0
- data/github_ci/ruby3.3.gemfile +17 -0
- data/github_ci/ruby3.3.gemfile.lock +217 -0
- data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/delay_execution.rb +4 -4
- data/lib/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +40 -0
- data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/dequeue_from_lock_queue.rb +17 -8
- data/lib/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rb +166 -0
- data/lib/redis_queued_locks/acquirer/acquire_lock/log_visitor.rb +218 -0
- data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rb +543 -0
- data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/try_to_lock.rb +126 -92
- data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/with_acq_timeout.rb +14 -13
- data/lib/redis_queued_locks/acquirer/acquire_lock/yield_expire/log_visitor.rb +76 -0
- data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/yield_expire.rb +43 -20
- data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock.rb +69 -42
- data/lib/redis_queued_locks/{acquier → acquirer}/clear_dead_requests.rb +5 -3
- data/lib/redis_queued_locks/{acquier → acquirer}/extend_lock_ttl.rb +4 -3
- data/lib/redis_queued_locks/{acquier → acquirer}/is_locked.rb +1 -1
- data/lib/redis_queued_locks/{acquier → acquirer}/is_queued.rb +1 -1
- data/lib/redis_queued_locks/{acquier → acquirer}/keys.rb +5 -5
- data/lib/redis_queued_locks/{acquier → acquirer}/lock_info.rb +9 -5
- data/lib/redis_queued_locks/{acquier → acquirer}/locks.rb +16 -3
- data/lib/redis_queued_locks/{acquier → acquirer}/queue_info.rb +8 -6
- data/lib/redis_queued_locks/{acquier → acquirer}/queues.rb +9 -2
- data/lib/redis_queued_locks/{acquier → acquirer}/release_all_locks.rb +23 -18
- data/lib/redis_queued_locks/{acquier → acquirer}/release_lock.rb +25 -19
- data/lib/redis_queued_locks/acquirer.rb +18 -0
- data/lib/redis_queued_locks/client.rb +164 -254
- data/lib/redis_queued_locks/config/dsl.rb +94 -0
- data/lib/redis_queued_locks/config.rb +231 -0
- data/lib/redis_queued_locks/data.rb +2 -0
- data/lib/redis_queued_locks/errors.rb +27 -11
- data/lib/redis_queued_locks/instrument.rb +11 -4
- data/lib/redis_queued_locks/logging/void_logger.rb +38 -1
- data/lib/redis_queued_locks/logging.rb +20 -5
- data/lib/redis_queued_locks/resource.rb +49 -11
- data/lib/redis_queued_locks/swarm/acquirers.rb +17 -16
- data/lib/redis_queued_locks/swarm/flush_zombies.rb +26 -25
- data/lib/redis_queued_locks/swarm/probe_hosts.rb +20 -19
- data/lib/redis_queued_locks/swarm/redis_client_builder.rb +3 -3
- data/lib/redis_queued_locks/swarm/supervisor.rb +19 -6
- data/lib/redis_queued_locks/swarm/swarm_element/isolated.rb +20 -18
- data/lib/redis_queued_locks/swarm/swarm_element/threaded.rb +35 -27
- data/lib/redis_queued_locks/swarm/zombie_info.rb +9 -9
- data/lib/redis_queued_locks/swarm.rb +20 -41
- data/lib/redis_queued_locks/utilities/lock.rb +4 -2
- data/lib/redis_queued_locks/utilities.rb +2 -2
- data/lib/redis_queued_locks/version.rb +2 -2
- data/lib/redis_queued_locks.rb +2 -2
- data/rbs_collection.lock.yaml +40 -0
- data/rbs_collection.yaml +16 -0
- data/redis_queued_locks.gemspec +22 -23
- data/sig/manifest.yml +7 -0
- data/sig/redis_queued_locks/acquier.rbs +4 -0
- data/sig/redis_queued_locks/acquirer/acquire_lock/delay_execution.rbs +9 -0
- data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rbs +21 -0
- data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue.rbs +26 -0
- data/sig/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rbs +71 -0
- data/sig/redis_queued_locks/acquirer/acquire_lock/log_visitor.rbs +72 -0
- data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rbs +179 -0
- data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rbs +48 -0
- data/sig/redis_queued_locks/acquirer/acquire_lock/with_acq_timeout.rbs +19 -0
- data/sig/redis_queued_locks/acquirer/acquire_lock/yield_expire.rbs +41 -0
- data/sig/redis_queued_locks/acquirer/acquire_lock/yield_with_expire/log_visitor.rbs +32 -0
- data/sig/redis_queued_locks/acquirer/acquire_lock.rbs +51 -0
- data/sig/redis_queued_locks/acquirer/clear_dead_requests.rbs +28 -0
- data/sig/redis_queued_locks/acquirer/extend_lock_ttl.rbs +28 -0
- data/sig/redis_queued_locks/acquirer/is_locked.rbs +9 -0
- data/sig/redis_queued_locks/acquirer/is_queued.rbs +9 -0
- data/sig/redis_queued_locks/acquirer/keys.rbs +10 -0
- data/sig/redis_queued_locks/acquirer/lock_info.rbs +10 -0
- data/sig/redis_queued_locks/acquirer/locks.rbs +16 -0
- data/sig/redis_queued_locks/acquirer/queue_info.rbs +13 -0
- data/sig/redis_queued_locks/acquirer/queues.rbs +16 -0
- data/sig/redis_queued_locks/acquirer/release_all_locks.rbs +30 -0
- data/sig/redis_queued_locks/acquirer/release_lock.rbs +38 -0
- data/sig/redis_queued_locks/client.rbs +195 -0
- data/sig/redis_queued_locks/config/dsl.rbs +26 -0
- data/sig/redis_queued_locks/config.rbs +23 -0
- data/sig/redis_queued_locks/data.rbs +4 -0
- data/sig/redis_queued_locks/debugger/interface.rbs +9 -0
- data/sig/redis_queued_locks/debugger.rbs +13 -0
- data/sig/redis_queued_locks/errors.rbs +43 -0
- data/sig/redis_queued_locks/instrument/active_support.rbs +7 -0
- data/sig/redis_queued_locks/instrument/sampler.rbs +9 -0
- data/sig/redis_queued_locks/instrument/void_notifier.rbs +7 -0
- data/sig/redis_queued_locks/instrument.rbs +15 -0
- data/sig/redis_queued_locks/logging/sampler.rbs +9 -0
- data/sig/redis_queued_locks/logging/void_logger.rbs +15 -0
- data/sig/redis_queued_locks/logging.rbs +15 -0
- data/sig/redis_queued_locks/resource.rbs +42 -0
- data/sig/redis_queued_locks/swarm/acquirers.rbs +10 -0
- data/sig/redis_queued_locks/swarm/flush_zombies.rbs +13 -0
- data/sig/redis_queued_locks/swarm/probe_hosts.rbs +13 -0
- data/sig/redis_queued_locks/swarm/redis_client_builder.rbs +19 -0
- data/sig/redis_queued_locks/swarm/supervisor.rbs +26 -0
- data/sig/redis_queued_locks/swarm/swarm_element/isolated.rbs +52 -0
- data/sig/redis_queued_locks/swarm/swarm_element/threaded.rbs +61 -0
- data/sig/redis_queued_locks/swarm/swarm_element.rbs +8 -0
- data/sig/redis_queued_locks/swarm/zombie_info.rbs +24 -0
- data/sig/redis_queued_locks/swarm.rbs +41 -0
- data/sig/redis_queued_locks/utilities/lock.rbs +10 -0
- data/sig/redis_queued_locks/utilities.rbs +11 -0
- data/sig/redis_queued_locks/version.rbs +3 -0
- data/sig/redis_queued_locks.rbs +14 -0
- data/sig/vendor/active_support.rbs +9 -0
- data/sig/vendor/redis_client.rbs +39 -0
- data/sig/vendor/semantic_logger.rbs +4 -0
- metadata +96 -54
- data/lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +0 -40
- data/lib/redis_queued_locks/acquier/acquire_lock/instr_visitor.rb +0 -166
- data/lib/redis_queued_locks/acquier/acquire_lock/log_visitor.rb +0 -216
- data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock/log_visitor.rb +0 -541
- data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire/log_visitor.rb +0 -76
- data/lib/redis_queued_locks/acquier.rb +0 -18
data/README.md
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
# RedisQueuedLocks · ](https://badge.fury.io/rb/redis_queued_locks)
|
2
|
+
|
3
|
+
[](https://github.com/0exp/redis_queued_locks/actions) [](https://github.com/0exp/redis_queued_locks/actions) [![TypeCheck (Runtime) [RBS]](https://github.com/0exp/redis_queued_locks/actions/workflows/typecheck-runtime.yml/badge.svg?branch=master)](https://github.com/0exp/redis_queued_locks/actions) [![TypeCheck (Static) [Steep]](https://github.com/0exp/redis_queued_locks/actions/workflows/typecheck-static.yml/badge.svg?branch=master)](https://github.com/0exp/redis_queued_locks/actions)
|
2
4
|
|
3
5
|
<a href="https://redis.io/docs/manual/patterns/distributed-locks/">Distributed locks</a> with "prioritized lock acquisition queue" capabilities based on the Redis Database.
|
4
6
|
|
@@ -50,7 +52,7 @@ Provides flexible invocation flow, parametrized limits (lock request ttl, lock t
|
|
50
52
|
- [zombies_info](#zombies_info)
|
51
53
|
- [zombie_locks](#zombie_locks)
|
52
54
|
- [zombie_hosts](#zombie_hosts)
|
53
|
-
- [
|
55
|
+
- [zombie_acquirers](#zombie_acquirers)
|
54
56
|
- [Lock Access Strategies](#lock-access-strategies)
|
55
57
|
- [queued](#lock-access-strategies)
|
56
58
|
- [random](#lock-access-strategies)
|
@@ -152,29 +154,29 @@ redis_client = RedisClient.config.new_pool # NOTE: provide your own RedisClient
|
|
152
154
|
clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
|
153
155
|
# (default: 3) (supports nil)
|
154
156
|
# - nil means "infinite retries" and you are only limited by the "try_to_lock_timeout" config;
|
155
|
-
config
|
157
|
+
config['retry_count'] = 3
|
156
158
|
|
157
159
|
# (milliseconds) (default: 200)
|
158
|
-
config
|
160
|
+
config['retry_delay'] = 200
|
159
161
|
|
160
162
|
# (milliseconds) (default: 25)
|
161
|
-
config
|
163
|
+
config['retry_jitter'] = 25
|
162
164
|
|
163
165
|
# (seconds) (supports nil)
|
164
166
|
# - nil means "no timeout" and you are only limited by "retry_count" config;
|
165
|
-
config
|
167
|
+
config['try_to_lock_timeout'] = 10
|
166
168
|
|
167
169
|
# (milliseconds) (default: 5_000)
|
168
170
|
# - lock's time to live
|
169
|
-
config
|
171
|
+
config['default_lock_ttl'] = 5_000
|
170
172
|
|
171
173
|
# (seconds) (default: 15)
|
172
174
|
# - lock request timeout. after this timeout your lock request in queue will be requeued with new position (at the end of the queue);
|
173
|
-
config
|
175
|
+
config['default_queue_ttl'] = 15
|
174
176
|
|
175
177
|
# (boolean) (default: false)
|
176
178
|
# - should be all blocks of code are timed by default;
|
177
|
-
config
|
179
|
+
config['is_timed_by_default'] = false
|
178
180
|
|
179
181
|
# (boolean) (default: false)
|
180
182
|
# - When the lock acquirement try reached the acquirement time limit (:timeout option) the
|
@@ -197,7 +199,7 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
|
|
197
199
|
# and moved from the lock queue after the error moment and before the error message build;
|
198
200
|
# - You should consider the async nature of this error message and should use received data
|
199
201
|
# from error message correspondingly;
|
200
|
-
config
|
202
|
+
config['detailed_acq_timeout_error'] = false
|
201
203
|
|
202
204
|
# (symbol) (default: :queued)
|
203
205
|
# - Defines the way in which the lock should be obitained;
|
@@ -208,7 +210,7 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
|
|
208
210
|
# - `:queued` (FIFO): the classic queued behavior (default), your lock will be obitaned if you are first in queue and the required lock is free;
|
209
211
|
# - `:random` (RANDOM): obtain a lock without checking the positions in the queue (but with checking the limist,
|
210
212
|
# retries, timeouts and so on). if lock is free to obtain - it will be obtained;
|
211
|
-
config
|
213
|
+
config['default_access_strategy'] = :queued
|
212
214
|
|
213
215
|
# (symbol) (default: :wait_for_lock)
|
214
216
|
# - Global default conflict strategy mode;
|
@@ -222,23 +224,23 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
|
|
222
224
|
# - `:wait_for_lock` - (default) - work in classic way (with timeouts, retry delays, retry limits, etc - in classic way :));
|
223
225
|
# - `:dead_locking` - fail with deadlock exception;
|
224
226
|
# - See "Dead locks and Reentrant Locks" documentation section in REDME.md for details;
|
225
|
-
config
|
227
|
+
config['default_conflict_strategy'] = :wait_for_lock
|
226
228
|
|
227
229
|
# (default: 100)
|
228
230
|
# - how many items will be released at a time in #clear_locks and in #clear_dead_requests (uses SCAN);
|
229
231
|
# - affects the performance of your Redis and Ruby Application (configure thoughtfully);
|
230
|
-
config
|
232
|
+
config['lock_release_batch_size'] = 100
|
231
233
|
|
232
234
|
# (default: 500)
|
233
235
|
# - how many items should be extracted from redis during the #locks, #queues, #keys
|
234
236
|
# #locks_info, and #queues_info operations (uses SCAN);
|
235
237
|
# - affects the performance of your Redis and Ruby Application (configure thoughtfully;)
|
236
|
-
config
|
238
|
+
config['key_extraction_batch_size'] = 500
|
237
239
|
|
238
240
|
# (default: 1 day)
|
239
241
|
# - the default period of time (in milliseconds) after which a lock request is considered dead;
|
240
242
|
# - used for `#clear_dead_requests` as default vaule of `:dead_ttl` option;
|
241
|
-
config
|
243
|
+
config['dead_request_ttl'] = (1 * 24 * 60 * 60 * 1000) # one day in milliseconds
|
242
244
|
|
243
245
|
# (default: RedisQueuedLocks::Instrument::VoidNotifier)
|
244
246
|
# - instrumentation layer;
|
@@ -246,16 +248,16 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
|
|
246
248
|
# - event: <string> requried;
|
247
249
|
# - payload: <hash> requried;
|
248
250
|
# - disabled by default via `VoidNotifier`;
|
249
|
-
config
|
251
|
+
config['instrumenter'] = RedisQueuedLocks::Instrument::ActiveSupport
|
250
252
|
|
251
253
|
# (default: -> { RedisQueuedLocks::Resource.calc_uniq_identity })
|
252
254
|
# - uniqude idenfitier that is uniq per process/pod;
|
253
255
|
# - prevents potential lock-acquirement collisions bettween different process/pods
|
254
|
-
# that have identical process_id/thread_id/fiber_id/ractor_id (identivcal
|
256
|
+
# that have identical process_id/thread_id/fiber_id/ractor_id (identivcal acquirer ids);
|
255
257
|
# - it is calculated once per `RedisQueudLocks::Client` instance;
|
256
258
|
# - expects the proc object;
|
257
259
|
# - `SecureRandom.hex(8)` by default;
|
258
|
-
config
|
260
|
+
config['uniq_identifier'] = -> { RedisQueuedLocks::Resource.calc_uniq_identity }
|
259
261
|
|
260
262
|
# (default: RedisQueuedLocks::Logging::VoidLogger)
|
261
263
|
# - the logger object;
|
@@ -264,7 +266,7 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
|
|
264
266
|
# - at this moment the only debug logs are realised in following cases:
|
265
267
|
# - "[redis_queued_locks.start_lock_obtaining]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
|
266
268
|
# - "[redis_queued_locks.start_try_to_lock_cycle]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
|
267
|
-
# - "[redis_queued_locks.
|
269
|
+
# - "[redis_queued_locks.dead_score_reached__reset_acquirer_position]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
|
268
270
|
# - "[redis_queued_locks.lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acq_time", "acs_strat");
|
269
271
|
# - "[redis_queued_locks.extendable_reentrant_lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acq_time", "acs_strat");
|
270
272
|
# - "[redis_queued_locks.reentrant_lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acq_time", "acs_strat");
|
@@ -272,7 +274,7 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
|
|
272
274
|
# - "[redis_queued_locks.expire_lock]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
|
273
275
|
# - "[redis_queued_locks.decrease_lock]" (logs "lock_key", "decreased_ttl", "queue_ttl", "acq_id", "hst_id", "acs_strat");
|
274
276
|
# - by default uses VoidLogger that does nothing;
|
275
|
-
config
|
277
|
+
config['logger'] = RedisQueuedLocks::Logging::VoidLogger
|
276
278
|
|
277
279
|
# (default: false)
|
278
280
|
# - adds additional debug logs;
|
@@ -291,49 +293,49 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
|
|
291
293
|
# - "[redis_queued_locks.try_lock.exit__no_first]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat", "first_acq_id_in_queue", "<current_lock_data>");
|
292
294
|
# - "[redis_queued_locks.try_lock.exit__lock_still_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat", "first_acq_id_in_queue", "locked_by_acq_id", "<current_lock_data>");
|
293
295
|
# - "[redis_queued_locks.try_lock.obtain__free_to_acquire]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
|
294
|
-
config
|
296
|
+
config['log_lock_try'] = false
|
295
297
|
|
296
298
|
# (default: false)
|
297
299
|
# - enables <log sampling>: only the configured percent of RQL cases will be logged;
|
298
300
|
# - disabled by default;
|
299
|
-
# - works in tandem with <config
|
300
|
-
config
|
301
|
+
# - works in tandem with <config['log_sampling_percent']> and <config['log_sampler']> configs;
|
302
|
+
config['log_sampling_enabled'] = false
|
301
303
|
|
302
304
|
# (default: 15)
|
303
305
|
# - the percent of cases that should be logged;
|
304
|
-
# - take an effect when <config
|
305
|
-
# - works in tandem with <config
|
306
|
-
config
|
306
|
+
# - take an effect when <config['log_sampling_enalbed']> is true;
|
307
|
+
# - works in tandem with <config['log_sampling_enabled']> and <config['log_sampler']> configs;
|
308
|
+
config['log_sampling_percent'] = 15
|
307
309
|
|
308
310
|
# (default: RedisQueuedLocks::Logging::Sampler)
|
309
311
|
# - percent-based log sampler that decides should be RQL case logged or not;
|
310
|
-
# - works in tandem with <config
|
312
|
+
# - works in tandem with <config['log_sampling_enabled']> and <config['log_sampling_percent']> configs;
|
311
313
|
# - based on the ultra simple percent-based (weight-based) algorithm that uses SecureRandom.rand
|
312
314
|
# method so the algorithm error is ~(0%..13%);
|
313
315
|
# - you can provide your own log sampler with bettter algorithm that should realize
|
314
316
|
# `sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Logging::Sampler` for example);
|
315
|
-
config
|
317
|
+
config['log_sampler'] = RedisQueuedLocks::Logging::Sampler
|
316
318
|
|
317
319
|
# (default: false)
|
318
320
|
# - enables <instrumentaion sampling>: only the configured percent of RQL cases will be instrumented;
|
319
321
|
# - disabled by default;
|
320
|
-
# - works in tandem with <config
|
321
|
-
config
|
322
|
+
# - works in tandem with <config['instr_sampling_percent'] and <config['instr_sampler']>;
|
323
|
+
config['nstr_sampling_enabled'] = false
|
322
324
|
|
323
325
|
# (default: 15)
|
324
326
|
# - the percent of cases that should be instrumented;
|
325
|
-
# - take an effect when <config
|
326
|
-
# - works in tandem with <config
|
327
|
-
config
|
327
|
+
# - take an effect when <config['instr_sampling_enalbed']> is true;
|
328
|
+
# - works in tandem with <config['instr_sampling_enabled']> and <config['instr_sampler']> configs;
|
329
|
+
config['instr_sampling_percent'] = 15
|
328
330
|
|
329
331
|
# (default: RedisQueuedLocks::Instrument::Sampler)
|
330
332
|
# - percent-based log sampler that decides should be RQL case instrumented or not;
|
331
|
-
# - works in tandem with <config
|
333
|
+
# - works in tandem with <config['instr_sampling_enabled']> and <config['instr_sampling_percent']> configs;
|
332
334
|
# - based on the ultra simple percent-based (weight-based) algorithm that uses SecureRandom.rand
|
333
335
|
# method so the algorithm error is ~(0%..13%);
|
334
336
|
# - you can provide your own log sampler with bettter algorithm that should realize
|
335
337
|
# `sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Instrument::Sampler` for example);
|
336
|
-
config
|
338
|
+
config['instr_sampler'] = RedisQueuedLocks::Instrument::Sampler
|
337
339
|
end
|
338
340
|
```
|
339
341
|
|
@@ -375,36 +377,36 @@ end
|
|
375
377
|
- the block's result will be returned;
|
376
378
|
- If block is not passed:
|
377
379
|
- the obtained lock will be released after lock's ttl;
|
378
|
-
- the lock information will be returned (hash with technical info that contains: lock key,
|
380
|
+
- the lock information will be returned (hash with technical info that contains: lock key, acquirer identifier, acquirement timestamp, lock's ttl, type of obtaining process, etc);
|
379
381
|
|
380
382
|
```ruby
|
381
383
|
def lock(
|
382
384
|
lock_name,
|
383
|
-
ttl: config[
|
384
|
-
queue_ttl: config[
|
385
|
-
timeout: config[
|
386
|
-
timed: config[
|
387
|
-
retry_count: config[
|
388
|
-
retry_delay: config[
|
389
|
-
retry_jitter: config[
|
385
|
+
ttl: config['default_lock_ttl'],
|
386
|
+
queue_ttl: config['default_queue_ttl'],
|
387
|
+
timeout: config['try_to_lock_timeout'],
|
388
|
+
timed: config['is_timed_by_default'],
|
389
|
+
retry_count: config['retry_count'],
|
390
|
+
retry_delay: config['retry_delay'],
|
391
|
+
retry_jitter: config['retry_jitter'],
|
390
392
|
raise_errors: false,
|
391
393
|
fail_fast: false,
|
392
|
-
conflict_strategy: config[
|
393
|
-
access_strategy: config[
|
394
|
-
identity: uniq_identity, # (attr_accessor) calculated during client instantiation via config[
|
394
|
+
conflict_strategy: config['default_conflict_strategy'],
|
395
|
+
access_strategy: config['default_access_strategy'],
|
396
|
+
identity: uniq_identity, # (attr_accessor) calculated during client instantiation via config['uniq_identifier'] proc;
|
395
397
|
meta: nil,
|
396
|
-
detailed_acq_timeout_error: config[
|
398
|
+
detailed_acq_timeout_error: config['detailed_acq_timeout_error'],
|
397
399
|
instrument: nil,
|
398
|
-
instrumenter: config[
|
399
|
-
logger: config[
|
400
|
-
log_lock_try: config[
|
401
|
-
log_sampling_enabled: config[
|
402
|
-
log_sampling_percent: config[
|
403
|
-
log_sampler: config[
|
400
|
+
instrumenter: config['instrumenter'],
|
401
|
+
logger: config['logger'],
|
402
|
+
log_lock_try: config['log_lock_try'],
|
403
|
+
log_sampling_enabled: config['log_sampling_enabled'],
|
404
|
+
log_sampling_percent: config['log_sampling_percent'],
|
405
|
+
log_sampler: config['log_sampler'],
|
404
406
|
log_sample_this: false,
|
405
|
-
instr_sampling_enabled: config[
|
406
|
-
instr_sampling_percent: config[
|
407
|
-
instr_sampler: config[
|
407
|
+
instr_sampling_enabled: config['instr_sampling_enabled'],
|
408
|
+
instr_sampling_percent: config['instr_sampling_percent'],
|
409
|
+
instr_sampler: config['instr_sampler'],
|
408
410
|
instr_sample_this: false,
|
409
411
|
&block
|
410
412
|
)
|
@@ -414,30 +416,30 @@ def lock(
|
|
414
416
|
- Lock name to be obtained.
|
415
417
|
- `ttl` - (optional) - [Integer]
|
416
418
|
- Lock's time to live (in milliseconds);
|
417
|
-
- pre-configured in `config[
|
419
|
+
- pre-configured in `config['default_lock_ttl']`;
|
418
420
|
- `queue_ttl` - (optional) `[Integer]`
|
419
421
|
- Lifetime of the acuier's lock request. In seconds.
|
420
|
-
- pre-configured in `config[
|
422
|
+
- pre-configured in `config['default_queue_ttl']`;
|
421
423
|
- `timeout` - (optional) `[Integer,NilClass]`
|
422
424
|
- Time period a client should try to acquire the lock (in seconds). Nil means "without timeout".
|
423
|
-
- pre-configured in `config[
|
425
|
+
- pre-configured in `config['try_to_lock_timeout']`;
|
424
426
|
- `timed` - (optiona) `[Boolean]`
|
425
427
|
- Limit the invocation time period of the passed block of code by the lock's TTL.
|
426
|
-
- pre-configured in `config[
|
428
|
+
- pre-configured in `config['is_timed_by_default']`;
|
427
429
|
- `false` by default;
|
428
430
|
- `retry_count` - (optional) `[Integer,NilClass]`
|
429
431
|
- How many times we should try to acquire a lock. Nil means "infinite retries".
|
430
|
-
- pre-configured in `config[
|
432
|
+
- pre-configured in `config['retry_count']`;
|
431
433
|
- `retry_delay` - (optional) `[Integer]`
|
432
434
|
- A time-interval between the each retry (in milliseconds).
|
433
|
-
- pre-configured in `config[
|
435
|
+
- pre-configured in `config['retry_delay']`;
|
434
436
|
- `retry_jitter` - (optional) `[Integer]`
|
435
437
|
- Time-shift range for retry-delay (in milliseconds);
|
436
|
-
- pre-configured in `config[
|
438
|
+
- pre-configured in `config['retry_jitter']`;
|
437
439
|
- `instrumenter` - (optional) `[#notify]`
|
438
440
|
- See RedisQueuedLocks::Instrument::ActiveSupport for example;
|
439
441
|
- See [Instrumentation](#instrumentation) section of docs;
|
440
|
-
- pre-configured in `config[
|
442
|
+
- pre-configured in `config['isntrumenter']` with void notifier (`RedisQueuedLocks::Instrumenter::VoidNotifier`);
|
441
443
|
- `instrument` - (optional) `[NilClass,Any]`
|
442
444
|
- Custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
|
443
445
|
- `nil` by default (means "no custom instrumentation data");
|
@@ -457,13 +459,13 @@ def lock(
|
|
457
459
|
- `:queued` (FIFO): (default) the classic queued behavior, your lock will be obitaned if you are first in queue and the required lock is free;
|
458
460
|
- `:random` (RANDOM): obtain a lock without checking the positions in the queue (but with checking the limist, retries, timeouts and so on).
|
459
461
|
if lock is free to obtain - it will be obtained;
|
460
|
-
- pre-configured in `config[
|
462
|
+
- pre-configured in `config['default_access_strategy']`;
|
461
463
|
- See [Lock Access Strategies](#lock-access-strategies) documentation section for details;
|
462
464
|
- `conflict_strategy` - (optional) - `[Symbol]`
|
463
465
|
- The conflict strategy mode for cases when the process that obtained the lock
|
464
466
|
want to acquire this lock again;
|
465
467
|
- By default uses `:wait_for_lock` strategy;
|
466
|
-
- pre-confured in `config[
|
468
|
+
- pre-confured in `config['default_conflict_strategy']`;
|
467
469
|
- Strategies:
|
468
470
|
- `:work_through` - continue working under the lock **without** lock's TTL extension;
|
469
471
|
- `:extendable_work_through` - continue working under the lock **with** lock's TTL extension;
|
@@ -476,7 +478,7 @@ def lock(
|
|
476
478
|
pods or/and nodes of your application;
|
477
479
|
- It is calculated once during `RedisQueuedLock::Client` instantiation and stored in `@uniq_identity`
|
478
480
|
ivar (accessed via `uniq_dentity` accessor method);
|
479
|
-
- Identity calculator is pre-configured in `config[
|
481
|
+
- Identity calculator is pre-configured in `config['uniq_identifier']`;
|
480
482
|
- `meta` - (optional) `[NilClass,Hash<String|Symbol,Any>]`
|
481
483
|
- A custom metadata wich will be passed to the lock data in addition to the existing data;
|
482
484
|
- Custom metadata can not contain reserved lock data keys (such as `lock_key`, `acq_id`, `ts`, `ini_ttl`, `rem_ttl`);
|
@@ -499,24 +501,24 @@ def lock(
|
|
499
501
|
and moved from the lock queue after the error moment and before the error message build;
|
500
502
|
- You should consider the async nature of this error message and should use received data
|
501
503
|
from error message correspondingly;
|
502
|
-
- pre-configred in `config[
|
504
|
+
- pre-configred in `config['detailed_acq_timeout_error']`;
|
503
505
|
- `logger` - (optional) `[::Logger,#debug]`
|
504
506
|
- Logger object used for loggin internal mutation oeprations and opertioan results / process progress;
|
505
|
-
- pre-configured in `config[
|
507
|
+
- pre-configured in `config['logger']` with void logger `RedisQueuedLocks::Logging::VoidLogger`;
|
506
508
|
- `log_lock_try` - (optional) `[Boolean]`
|
507
509
|
- should be logged the each try of lock acquiring (a lot of logs can be generated depending on your retry configurations);
|
508
|
-
- pre-configured in `config[
|
510
|
+
- pre-configured in `config['log_lock_try']`;
|
509
511
|
- `false` by default;
|
510
512
|
- `log_sampling_enabled` - (optional) `[Boolean]`
|
511
513
|
- enables **log sampling**: only the configured percent of RQL cases will be logged;
|
512
514
|
- disabled by default;
|
513
515
|
- works in tandem with `log_sampling_percent` and `log_sampler` options;
|
514
|
-
- pre-configured in `config[
|
516
|
+
- pre-configured in `config['log_sampling_enabled']`;
|
515
517
|
- `log_sampling_percent` - (optional) `[Integer]`
|
516
518
|
- the percent of cases that should be logged;
|
517
519
|
- take an effect when `log_sampling_enalbed` is true;
|
518
520
|
- works in tandem with `log_sampling_enabled` and `log_sampler` options;
|
519
|
-
- pre-configured in `config[
|
521
|
+
- pre-configured in `config['log_sampling_percent']`;
|
520
522
|
- `log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
|
521
523
|
- percent-based log sampler that decides should be RQL case logged or not;
|
522
524
|
- works in tandem with `log_sampling_enabled` and `log_sampling_percent` options;
|
@@ -524,7 +526,7 @@ def lock(
|
|
524
526
|
method so the algorithm error is ~(0%..13%);
|
525
527
|
- you can provide your own log sampler with bettter algorithm that should realize
|
526
528
|
`sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Logging::Sampler` for example);
|
527
|
-
- pre-configured in `config[
|
529
|
+
- pre-configured in `config['log_sampler']`;
|
528
530
|
- `log_sample_this` - (optional) `[Boolean]`
|
529
531
|
- marks the method that everything should be logged despite the enabled log sampling;
|
530
532
|
- makes sense when log sampling is enabled;
|
@@ -533,12 +535,12 @@ def lock(
|
|
533
535
|
- enables **instrumentaion sampling**: only the configured percent of RQL cases will be instrumented;
|
534
536
|
- disabled by default;
|
535
537
|
- works in tandem with `instr_sampling_percent` and `instr_sampler` options;
|
536
|
-
- pre-configured in `config[
|
538
|
+
- pre-configured in `config['instr_sampling_enabled']`;
|
537
539
|
- `instr_sampling_percent` - (optional) `[Integer]`
|
538
540
|
- the percent of cases that should be instrumented;
|
539
541
|
- take an effect when `instr_sampling_enalbed` is true;
|
540
542
|
- works in tandem with `instr_sampling_enabled` and `instr_sampler` options;
|
541
|
-
- pre-configured in `config[
|
543
|
+
- pre-configured in `config['instr_sampling_percent']`;
|
542
544
|
- `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
|
543
545
|
- percent-based log sampler that decides should be RQL case instrumented or not;
|
544
546
|
- works in tandem with `instr_sampling_enabled` and `instr_sampling_percent` options;
|
@@ -546,7 +548,7 @@ def lock(
|
|
546
548
|
method so the algorithm error is ~(0%..13%);
|
547
549
|
- you can provide your own log sampler with bettter algorithm that should realize
|
548
550
|
`sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Instrument::Sampler` for example);
|
549
|
-
- pre-configured in `config[
|
551
|
+
- pre-configured in `config['instr_sampler']`;
|
550
552
|
- `instr_sample_this` - (optional) `[Boolean]`
|
551
553
|
- marks the method that everything should be instrumneted despite the enabled instrumentation sampling;
|
552
554
|
- makes sense when instrumentation sampling is enabled;
|
@@ -594,8 +596,8 @@ Return value:
|
|
594
596
|
{
|
595
597
|
ok: true,
|
596
598
|
result: {
|
597
|
-
lock_key: String, #
|
598
|
-
acq_id: String, #
|
599
|
+
lock_key: String, # acquirerd lock key ("rql:lock:your_lock_name")
|
600
|
+
acq_id: String, # acquirer identifier ("process_id/thread_id/fiber_id/ractor_id/identity")
|
599
601
|
hst_id: String, # host identifier ("process_id/thread_id/ractor_id/identity")
|
600
602
|
ts: Float, # time (epoch) when lock was obtained (float, Time#to_f)
|
601
603
|
ttl: Integer, # lock's time to live in milliseconds (integer)
|
@@ -786,37 +788,37 @@ rql.lock('my_lock', retry_delay: 3000, ttl: 3000, access_strategy: :random)
|
|
786
788
|
- `#lock!` - exceptional lock obtaining;
|
787
789
|
- fails when (and with):
|
788
790
|
- (`RedisQueuedLocks::LockAlreadyObtainedError`) when `fail_fast` is `true` and lock is already obtained;
|
789
|
-
- (`RedisQueuedLocks::
|
790
|
-
- (`RedisQueuedLocks::
|
791
|
+
- (`RedisQueuedLocks::LockAcquirementTimeoutError`) `timeout` limit reached before lock is obtained;
|
792
|
+
- (`RedisQueuedLocks::LockAcquirementRetryLimitError`) `retry_count` limit reached before lock is obtained;
|
791
793
|
- (`RedisQueuedLocks::ConflictLockObtainError`) when `conflict_strategy: :dead_locking` is used and the "same-process-dead-lock" is happened (see [Deadlocks and Reentrant locks](#deadlocks-and-reentrant-locks) for details);
|
792
794
|
|
793
795
|
```ruby
|
794
796
|
def lock!(
|
795
797
|
lock_name,
|
796
|
-
ttl: config[
|
797
|
-
queue_ttl: config[
|
798
|
-
timeout: config[
|
799
|
-
timed: config[
|
800
|
-
retry_count: config[
|
801
|
-
retry_delay: config[
|
802
|
-
retry_jitter: config[
|
798
|
+
ttl: config['default_lock_ttl'],
|
799
|
+
queue_ttl: config['default_queue_ttl'],
|
800
|
+
timeout: config['try_to_lock_timeout'],
|
801
|
+
timed: config['is_timed_by_default'],
|
802
|
+
retry_count: config['retry_count'],
|
803
|
+
retry_delay: config['retry_delay'],
|
804
|
+
retry_jitter: config['retry_jitter'],
|
803
805
|
fail_fast: false,
|
804
806
|
identity: uniq_identity,
|
805
807
|
meta: nil,
|
806
|
-
detailed_acq_timeout_error: config[
|
807
|
-
logger: config[
|
808
|
-
log_lock_try: config[
|
808
|
+
detailed_acq_timeout_error: config['detailed_acq_timeout_error']
|
809
|
+
logger: config['logger'],
|
810
|
+
log_lock_try: config['log_lock_try'],
|
809
811
|
instrument: nil,
|
810
|
-
instrumenter: config[
|
811
|
-
access_strategy: config[
|
812
|
-
conflict_strategy: config[
|
813
|
-
log_sampling_enabled: config[
|
814
|
-
log_sampling_percent: config[
|
815
|
-
log_sampler: config[
|
812
|
+
instrumenter: config['instrumenter'],
|
813
|
+
access_strategy: config['default_access_strategy'],
|
814
|
+
conflict_strategy: config['default_conflict_strategy'],
|
815
|
+
log_sampling_enabled: config['log_sampling_enabled'],
|
816
|
+
log_sampling_percent: config['log_sampling_percent'],
|
817
|
+
log_sampler: config['log_sampler'],
|
816
818
|
log_sample_this: false,
|
817
|
-
instr_sampling_enabled: config[
|
818
|
-
instr_sampling_percent: config[
|
819
|
-
instr_sampler: config[
|
819
|
+
instr_sampling_enabled: config['instr_sampling_enabled'],
|
820
|
+
instr_sampling_percent: config['instr_sampling_percent'],
|
821
|
+
instr_sampler: config['instr_sampler'],
|
820
822
|
instr_sample_this: false,
|
821
823
|
&block
|
822
824
|
)
|
@@ -834,7 +836,7 @@ See `#lock` method [documentation](#lock---obtain-a-lock).
|
|
834
836
|
- returns `nil` if lock does not exist;
|
835
837
|
- lock data (`Hash<String,String|Integer>`):
|
836
838
|
- `"lock_key"` - `string` - lock key in redis;
|
837
|
-
- `"acq_id"` - `string` -
|
839
|
+
- `"acq_id"` - `string` - acquirer identifier (process_id/thread_id/fiber_id/ractor_id/identity);
|
838
840
|
- `"hst_id"` - `string` - host identifier (process_id/thread_id/ractor_id/identity);
|
839
841
|
- `"ts"` - `numeric`/`epoch` - the time when lock was obtained;
|
840
842
|
- `"init_ttl"` - `integer` - (milliseconds) initial lock key ttl;
|
@@ -885,7 +887,7 @@ rql.lock_info("your_lock_name")
|
|
885
887
|
|
886
888
|
```ruby
|
887
889
|
# <for reentrant locks>
|
888
|
-
# (see `conflict_strategy:` kwarg attribute of #lock/#lock! methods and `config
|
890
|
+
# (see `conflict_strategy:` kwarg attribute of #lock/#lock! methods and `config['default_conflict_strategy']` config)
|
889
891
|
|
890
892
|
rql.lock("your_lock_name", ttl: 5_000)
|
891
893
|
rql.lock("your_lock_name", ttl: 3_000)
|
@@ -927,12 +929,12 @@ you can receive the lock queue info with empty queue value (an empty array).
|
|
927
929
|
- queue represents the ordered set of lock key reqests:
|
928
930
|
- set is ordered by score in ASC manner (inside the Redis Set);
|
929
931
|
- score is represented as a timestamp when the lock request was made;
|
930
|
-
- represents the
|
932
|
+
- represents the acquirer identifier and their score as an array of hashes;
|
931
933
|
- returns `nil` if lock queue does not exist;
|
932
934
|
- lock queue data (`Hash<String,String|Array<Hash<String|Numeric>>`):
|
933
935
|
- `"lock_queue"` - `string` - lock queue key in redis;
|
934
936
|
- `"queue"` - `array` - an array of lock requests (array of hashes):
|
935
|
-
- `"acq_id"` - `string` -
|
937
|
+
- `"acq_id"` - `string` - acquirer identifier (process_id/thread_id/fiber_id/ractor_id/identity by default);
|
936
938
|
- `"score"` - `float`/`epoch` - time when the lock request was made (epoch);
|
937
939
|
|
938
940
|
```ruby
|
@@ -987,35 +989,35 @@ rql.queued?("your_lock_name") # => true/false
|
|
987
989
|
- `lock_name` - (required) `[String]` - the lock name that should be released.
|
988
990
|
- `:logger` - (optional) `[::Logger,#debug]`
|
989
991
|
- custom logger object;
|
990
|
-
- pre-configured in `config[
|
992
|
+
- pre-configured in `config['logger']`;
|
991
993
|
- `:instrumenter` - (optional) `[#notify]`
|
992
994
|
- custom instrumenter object;
|
993
|
-
- pre-configured in `config[
|
995
|
+
- pre-configured in `config['instrumetner']`;
|
994
996
|
- `:instrument` - (optional) `[NilClass,Any]`;
|
995
997
|
- custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
|
996
998
|
- `nil` by default (no additional data);
|
997
999
|
- `:log_sampling_enabled` - (optional) `[Boolean]`
|
998
1000
|
- enables **log sampling**;
|
999
|
-
- pre-configured in `config[
|
1001
|
+
- pre-configured in `config['log_sampling_enabled']`;
|
1000
1002
|
- `:log_sampling_percent` - (optional) `[Integer]`
|
1001
1003
|
- **log sampling**:the percent of cases that should be logged;
|
1002
|
-
- pre-configured in `config[
|
1004
|
+
- pre-configured in `config['log_sampling_percent']`;
|
1003
1005
|
- `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
|
1004
1006
|
- **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
|
1005
|
-
- pre-configured in `config[
|
1007
|
+
- pre-configured in `config['log_sampler']`;
|
1006
1008
|
- `log_sample_this` - (optional) `[Boolean]`
|
1007
1009
|
- marks the method that everything should be logged despite the enabled log sampling;
|
1008
1010
|
- makes sense when log sampling is enabled;
|
1009
1011
|
- `false` by default;
|
1010
1012
|
- `:instr_sampling_enabled` - (optional) `[Boolean]`
|
1011
1013
|
- enables **instrumentaion sampling**;
|
1012
|
-
- pre-configured in `config[
|
1014
|
+
- pre-configured in `config['instr_sampling_enabled']`;
|
1013
1015
|
- `instr_sampling_percent` - (optional) `[Integer]`
|
1014
1016
|
- the percent of cases that should be instrumented;
|
1015
|
-
- pre-configured in `config[
|
1017
|
+
- pre-configured in `config['instr_sampling_percent']`;
|
1016
1018
|
- `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
|
1017
1019
|
- percent-based log sampler that decides should be RQL case instrumented or not;
|
1018
|
-
- pre-configured in `config[
|
1020
|
+
- pre-configured in `config['instr_sampler']`;
|
1019
1021
|
- `instr_sample_this` - (optional) `[Boolean]`
|
1020
1022
|
- marks the method that everything should be instrumneted despite the enabled instrumentation sampling;
|
1021
1023
|
- makes sense when instrumentation sampling is enabled;
|
@@ -1062,37 +1064,37 @@ rql.unlock("your_lock_name")
|
|
1062
1064
|
- accepts:
|
1063
1065
|
- `:batch_size` - (optional) `[Integer]`
|
1064
1066
|
- the size of batch of locks and lock queus that should be cleared under the one pipelined redis command at once;
|
1065
|
-
- pre-configured in `config[
|
1067
|
+
- pre-configured in `config['lock_release_batch_size']`;
|
1066
1068
|
- `:logger` - (optional) `[::Logger,#debug]`
|
1067
1069
|
- custom logger object;
|
1068
|
-
- pre-configured value in `config[
|
1070
|
+
- pre-configured value in `config['logger']`;
|
1069
1071
|
- `:instrumenter` - (optional) `[#notify]`
|
1070
1072
|
- custom instrumenter object;
|
1071
|
-
- pre-configured value in `config[
|
1073
|
+
- pre-configured value in `config['isntrumenter']`;
|
1072
1074
|
- `:instrument` - (optional) `[NilClass,Any]`
|
1073
1075
|
- custom instrumentation data wich will be passed to the instrumenter's payload with `:instrument` key;
|
1074
1076
|
- `:log_sampling_enabled` - (optional) `[Boolean]`
|
1075
1077
|
- enables **log sampling**;
|
1076
|
-
- pre-configured in `config[
|
1078
|
+
- pre-configured in `config['log_sampling_enabled']`;
|
1077
1079
|
- `:log_sampling_percent` - (optional) `[Integer]`
|
1078
1080
|
- **log sampling**:the percent of cases that should be logged;
|
1079
|
-
- pre-configured in `config[
|
1081
|
+
- pre-configured in `config['log_sampling_percent']`;
|
1080
1082
|
- `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
|
1081
1083
|
- **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
|
1082
|
-
- pre-configured in `config[
|
1084
|
+
- pre-configured in `config['log_sampler']`;
|
1083
1085
|
- `log_sample_this` - (optional) `[Boolean]`
|
1084
1086
|
- marks the method that everything should be logged despite the enabled log sampling;
|
1085
1087
|
- makes sense when log sampling is enabled;
|
1086
1088
|
- `false` by default;
|
1087
1089
|
- `:instr_sampling_enabled` - (optional) `[Boolean]`
|
1088
1090
|
- enables **instrumentaion sampling**;
|
1089
|
-
- pre-configured in `config[
|
1091
|
+
- pre-configured in `config['instr_sampling_enabled']`;
|
1090
1092
|
- `instr_sampling_percent` - (optional) `[Integer]`
|
1091
1093
|
- the percent of cases that should be instrumented;
|
1092
|
-
- pre-configured in `config[
|
1094
|
+
- pre-configured in `config['instr_sampling_percent']`;
|
1093
1095
|
- `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
|
1094
1096
|
- percent-based log sampler that decides should be RQL case instrumented or not;
|
1095
|
-
- pre-configured in `config[
|
1097
|
+
- pre-configured in `config['instr_sampler']`;
|
1096
1098
|
- `instr_sample_this` - (optional) `[Boolean]`
|
1097
1099
|
- marks the method that everything should be instrumneted despite the enabled instrumentation sampling;
|
1098
1100
|
- makes sense when instrumentation sampling is enabled;
|
@@ -1131,35 +1133,35 @@ rql.clear_locks
|
|
1131
1133
|
- how many milliseconds should be added to the lock's TTL;
|
1132
1134
|
- `:instrumenter` - (optional) `[#notify]`
|
1133
1135
|
- custom instrumenter object;
|
1134
|
-
- pre-configured in `config[
|
1136
|
+
- pre-configured in `config['instrumetner']`;
|
1135
1137
|
- `:instrument` - (optional) `[NilClass,Any]`;
|
1136
1138
|
- custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
|
1137
1139
|
- `nil` by default (no additional data);
|
1138
1140
|
- `:logger` - (optional) `[::Logger,#debug]`
|
1139
1141
|
- custom logger object;
|
1140
|
-
- pre-configured in `config[
|
1142
|
+
- pre-configured in `config['logger']`;
|
1141
1143
|
- `:log_sampling_enabled` - (optional) `[Boolean]`
|
1142
1144
|
- enables **log sampling**;
|
1143
|
-
- pre-configured in `config[
|
1145
|
+
- pre-configured in `config['log_sampling_enabled']`;
|
1144
1146
|
- `:log_sampling_percent` - (optional) `[Integer]`
|
1145
1147
|
- **log sampling**:the percent of cases that should be logged;
|
1146
|
-
- pre-configured in `config[
|
1148
|
+
- pre-configured in `config['log_sampling_percent']`;
|
1147
1149
|
- `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
|
1148
1150
|
- **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
|
1149
|
-
- pre-configured in `config[
|
1151
|
+
- pre-configured in `config['log_sampler']`;
|
1150
1152
|
- `log_sample_this` - (optional) `[Boolean]`
|
1151
1153
|
- marks the method that everything should be logged despite the enabled log sampling;
|
1152
1154
|
- makes sense when log sampling is enabled;
|
1153
1155
|
- `false` by default;
|
1154
1156
|
- `:instr_sampling_enabled` - (optional) `[Boolean]`
|
1155
1157
|
- enables **instrumentaion sampling**;
|
1156
|
-
- pre-configured in `config[
|
1158
|
+
- pre-configured in `config['instr_sampling_enabled']`;
|
1157
1159
|
- `instr_sampling_percent` - (optional) `[Integer]`
|
1158
1160
|
- the percent of cases that should be instrumented;
|
1159
|
-
- pre-configured in `config[
|
1161
|
+
- pre-configured in `config['instr_sampling_percent']`;
|
1160
1162
|
- `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
|
1161
1163
|
- percent-based log sampler that decides should be RQL case instrumented or not;
|
1162
|
-
- pre-configured in `config[
|
1164
|
+
- pre-configured in `config['instr_sampler']`;
|
1163
1165
|
- `instr_sample_this` - (optional) `[Boolean]`
|
1164
1166
|
- marks the method that everything should be instrumneted despite the enabled instrumentation sampling;
|
1165
1167
|
- makes sense when instrumentation sampling is enabled;
|
@@ -1199,7 +1201,7 @@ rql.extend_lock_ttl("my_lock", 5_000) # NOTE: add 5_000 milliseconds
|
|
1199
1201
|
- get list of obtained locks;
|
1200
1202
|
- uses redis `SCAN` under the hood;
|
1201
1203
|
- accepts:
|
1202
|
-
- `:scan_size` - `Integer` - (`config[
|
1204
|
+
- `:scan_size` - `Integer` - (`config['key_extraction_batch_size']` by default);
|
1203
1205
|
- `:with_info` - `Boolean` - `false` by default (for details see [#locks_info](#locks_info---get-list-of-locks-with-their-info));
|
1204
1206
|
- returns:
|
1205
1207
|
- `Set<String>` (for `with_info: false`);
|
@@ -1232,7 +1234,7 @@ rql.locks # or rql.locks(scan_size: 123)
|
|
1232
1234
|
- get list of lock request queues;
|
1233
1235
|
- uses redis `SCAN` under the hood;
|
1234
1236
|
- accepts
|
1235
|
-
- `:scan_size` - `Integer` - (`config[
|
1237
|
+
- `:scan_size` - `Integer` - (`config['key_extraction_batch_size']` by default);
|
1236
1238
|
- `:with_info` - `Boolean` - `false` by default (for details see [#queues_info](#queues_info---get-list-of-queues-with-their-info));
|
1237
1239
|
- returns:
|
1238
1240
|
- `Set<String>` (for `with_info: false`);
|
@@ -1265,7 +1267,7 @@ rql.queues # or rql.queues(scan_size: 123)
|
|
1265
1267
|
- get list of taken locks and queues;
|
1266
1268
|
- uses redis `SCAN` under the hood;
|
1267
1269
|
- accepts:
|
1268
|
-
`:scan_size` - `Integer` - (`config[
|
1270
|
+
`:scan_size` - `Integer` - (`config['key_extraction_batch_size']` by default);
|
1269
1271
|
- returns: `Set<String>`
|
1270
1272
|
|
1271
1273
|
```ruby
|
@@ -1298,7 +1300,7 @@ rql.keys # or rql.keys(scan_size: 123)
|
|
1298
1300
|
|
1299
1301
|
- get list of locks with their info;
|
1300
1302
|
- uses redis `SCAN` under the hod;
|
1301
|
-
- accepts `scan_size:`/`Integer` option (`config[
|
1303
|
+
- accepts `scan_size:`/`Integer` option (`config['key_extraction_batch_size']` by default);
|
1302
1304
|
- returns `Set<Hash<Symbol,Any>>` (see [#lock_info](#lock_info) and examples below for details).
|
1303
1305
|
- contained data: `{ lock: String, status: Symbol, info: Hash<String,Any> }`;
|
1304
1306
|
- `:lock` - `String` - lock key in Redis;
|
@@ -1336,11 +1338,11 @@ rql.locks_info # or rql.locks_info(scan_size: 123)
|
|
1336
1338
|
|
1337
1339
|
- get list of queues with their info;
|
1338
1340
|
- uses redis `SCAN` under the hod;
|
1339
|
-
- accepts `scan_size:`/`Integer` option (`config[
|
1341
|
+
- accepts `scan_size:`/`Integer` option (`config['key_extraction_batch_size']` by default);
|
1340
1342
|
- returns `Set<Hash<Symbol,Any>>` (see [#queue_info](#queue_info) and examples below for details).
|
1341
1343
|
- contained data: `{ queue: String, requests: Array<Hash<String,Any>> }`
|
1342
1344
|
- `:queue` - `String` - lock key queue in Redis;
|
1343
|
-
- `:requests` - `Array<Hash<String,Any>>` - lock requests in the que with their
|
1345
|
+
- `:requests` - `Array<Hash<String,Any>>` - lock requests in the que with their acquirer id and score.
|
1344
1346
|
|
1345
1347
|
```ruby
|
1346
1348
|
rql.queues_info # or rql.qeuues_info(scan_size: 123)
|
@@ -1371,7 +1373,7 @@ For this case your lock reuquest will be cleared only when any process will try
|
|
1371
1373
|
to acquire this lock again (cuz lock acquirement triggers the removement of expired requests).
|
1372
1374
|
|
1373
1375
|
In order to help with these dead requests you may periodically call `#clear_dead_requests`
|
1374
|
-
with corresponding `:dead_ttl` option, that is pre-configured by default via `config[
|
1376
|
+
with corresponding `:dead_ttl` option, that is pre-configured by default via `config['dead_request_ttl']`.
|
1375
1377
|
|
1376
1378
|
`:dead_ttl` option is required because of it is no any **fast** and **resource-free** way to understand which request
|
1377
1379
|
is dead now and is it really dead cuz each request queue can host their requests with
|
@@ -1380,41 +1382,41 @@ a custom queue ttl for each request differently.
|
|
1380
1382
|
Accepts:
|
1381
1383
|
- `:dead_ttl` - (optional) `[Integer]`
|
1382
1384
|
- lock request ttl after which a lock request is considered dead;
|
1383
|
-
- has a preconfigured value in `config[
|
1385
|
+
- has a preconfigured value in `config['dead_request_ttl']` (1 day by default);
|
1384
1386
|
- `:sacn_size` - (optional) `[Integer]`
|
1385
1387
|
- the batch of scanned keys for Redis'es SCAN command;
|
1386
|
-
- has a preconfigured valie in `config[
|
1388
|
+
- has a preconfigured valie in `config['lock_release_batch_size']`;
|
1387
1389
|
- `:logger` - (optional) `[::Logger,#debug]`
|
1388
1390
|
- custom logger object;
|
1389
|
-
- pre-configured in `config[
|
1391
|
+
- pre-configured in `config['logger']`;
|
1390
1392
|
- `:instrumenter` - (optional) `[#notify]`
|
1391
1393
|
- custom instrumenter object;
|
1392
|
-
- pre-configured in `config[
|
1394
|
+
- pre-configured in `config['isntrumenter']`;
|
1393
1395
|
- `:instrument` - (optional) `[NilClass,Any]`
|
1394
1396
|
- custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
|
1395
1397
|
- `nil` by default (no additional data);
|
1396
1398
|
- `:log_sampling_enabled` - (optional) `[Boolean]`
|
1397
1399
|
- enables **log sampling**;
|
1398
|
-
- pre-configured in `config[
|
1400
|
+
- pre-configured in `config['log_sampling_enabled']`;
|
1399
1401
|
- `:log_sampling_percent` - (optional) `[Integer]`
|
1400
1402
|
- **log sampling**:the percent of cases that should be logged;
|
1401
|
-
- pre-configured in `config[
|
1403
|
+
- pre-configured in `config['log_sampling_percent']`;
|
1402
1404
|
- `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
|
1403
1405
|
- **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
|
1404
|
-
- pre-configured in `config[
|
1406
|
+
- pre-configured in `config['log_sampler']`;
|
1405
1407
|
- `log_sample_this` - (optional) `[Boolean]`
|
1406
1408
|
- marks the method that everything should be logged despite the enabled log sampling;
|
1407
1409
|
- makes sense when log sampling is enabled;
|
1408
1410
|
- `false` by default;
|
1409
1411
|
- `:instr_sampling_enabled` - (optional) `[Boolean]`
|
1410
1412
|
- enables **instrumentaion sampling**;
|
1411
|
-
- pre-configured in `config[
|
1413
|
+
- pre-configured in `config['instr_sampling_enabled']`;
|
1412
1414
|
- `instr_sampling_percent` - (optional) `[Integer]`
|
1413
1415
|
- the percent of cases that should be instrumented;
|
1414
|
-
- pre-configured in `config[
|
1416
|
+
- pre-configured in `config['instr_sampling_percent']`;
|
1415
1417
|
- `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
|
1416
1418
|
- percent-based log sampler that decides should be RQL case instrumented or not;
|
1417
|
-
- pre-configured in `config[
|
1419
|
+
- pre-configured in `config['instr_sampler']`;
|
1418
1420
|
- `instr_sample_this` - (optional) `[Boolean]`
|
1419
1421
|
- marks the method that everything should be instrumneted despite the enabled instrumentation sampling;
|
1420
1422
|
- makes sense when instrumentation sampling is enabled;
|
@@ -1464,7 +1466,7 @@ Accepts:
|
|
1464
1466
|
- `identity:` - (optional) `[String,Any]`;
|
1465
1467
|
- this value is calculated once during `RedisQueuedLock::Client` instantiation and stored in `@uniq_identity`;
|
1466
1468
|
- this value can be accessed from `RedisQueuedLock::Client#uniq_identity`;
|
1467
|
-
- [Configuration](#configuration) documentation: see `config[
|
1469
|
+
- [Configuration](#configuration) documentation: see `config['uniq_identifier']`;
|
1468
1470
|
- [#lock](#lock---obtain-a-lock) method documentation: see `uniq_identifier`;
|
1469
1471
|
|
1470
1472
|
```ruby
|
@@ -1505,7 +1507,7 @@ Accepts:
|
|
1505
1507
|
- `identity:` - (optional) `[String]`;
|
1506
1508
|
- this value is calculated once during `RedisQueuedLock::Client` instantiation and stored in `@uniq_identity`;
|
1507
1509
|
- this value can be accessed from `RedisQueuedLock::Client#uniq_identity`;
|
1508
|
-
- [Configuration](#configuration) documentation: see `config[
|
1510
|
+
- [Configuration](#configuration) documentation: see `config['uniq_identifier']`;
|
1509
1511
|
- [#lock](#lock---obtain-a-lock) method documentation: see `uniq_identifier`;
|
1510
1512
|
|
1511
1513
|
```ruby
|
@@ -1537,7 +1539,7 @@ Accepts:
|
|
1537
1539
|
- `identity` - (optional) `[String]`;
|
1538
1540
|
- this value is calculated once during `RedisQueuedLock::Client` instantiation and stored in `@uniq_identity`;
|
1539
1541
|
- this value can be accessed from `RedisQueuedLock::Client#uniq_identity`;
|
1540
|
-
- [Configuration](#configuration) documentation: see `config[
|
1542
|
+
- [Configuration](#configuration) documentation: see `config['uniq_identifier']`;
|
1541
1543
|
- [#lock](#lock---obtain-a-lock) method documentation: see `uniq_identifier`;
|
1542
1544
|
|
1543
1545
|
```ruby
|
@@ -1576,7 +1578,7 @@ rql.possible_host_ids
|
|
1576
1578
|
- [zombies_info](#zombies_info)
|
1577
1579
|
- [zombie_locks](#zombie_locks)
|
1578
1580
|
- [zombie_hosts](#zombie_hosts)
|
1579
|
-
- [
|
1581
|
+
- [zombie_acquirers](#zombie_acquirers)
|
1580
1582
|
|
1581
1583
|
<hr>
|
1582
1584
|
|
@@ -1592,31 +1594,31 @@ rql.possible_host_ids
|
|
1592
1594
|
|
1593
1595
|
clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
|
1594
1596
|
# NOTE: auto-swarm your RQL client after initalization (run swarm elements and their supervisor)
|
1595
|
-
config
|
1597
|
+
config['swarm.auto_swarm'] = false
|
1596
1598
|
|
1597
1599
|
# supervisor configs
|
1598
|
-
config
|
1600
|
+
config['swarm.supervisor.liveness_probing_period'] = 2 # NOTE: in seconds
|
1599
1601
|
|
1600
1602
|
# (probe_hosts) host probing configuration
|
1601
|
-
config
|
1602
|
-
config
|
1603
|
+
config['swarm.probe_hosts.enabled_for_swarm'] = true # NOTE: run host-probing from or not
|
1604
|
+
config['swarm.probe_hosts.probe_period'] = 2 # NOTE: (in seconds) the period of time when the probing process is triggered
|
1603
1605
|
# (probe_hosts) individual redis config
|
1604
|
-
config
|
1605
|
-
config
|
1606
|
-
config
|
1607
|
-
config
|
1606
|
+
config['swarm.probe_hosts.redis_config.sentinel'] = false # NOTE: individual redis config
|
1607
|
+
config['swarm.probe_hosts.redis_config.pooled'] = false # NOTE: individual redis config
|
1608
|
+
config['swarm.probe_hosts.redis_config.config'] = {} # NOTE: individual redis config
|
1609
|
+
config['swarm.probe_hosts.redis_config.pool_config'] = {} # NOTE: individual redis config
|
1608
1610
|
|
1609
1611
|
# (flush_zombies) zombie flushing configuration
|
1610
|
-
config
|
1611
|
-
config
|
1612
|
-
config
|
1613
|
-
config
|
1614
|
-
config
|
1612
|
+
config['swarm.flush_zombies.enabled_for_swarm'] = true # NOTE: run zombie flushing or not
|
1613
|
+
config['swarm.flush_zombies.zombie_flush_period'] = 10 # NOTE: (in seconds) period of time when the zombie flusher is triggered
|
1614
|
+
config['swarm.flush_zombies.zombie_ttl'] = 15_000 # NOTE: (in milliseconds) when the lock/host/acquirer is considered a zombie
|
1615
|
+
config['swarm.flush_zombies.zombie_lock_scan_size'] = 500 # NOTE: scan sizec during zombie flushing
|
1616
|
+
config['swarm.flush_zombies.zombie_queue_scan_size'] = 500 # NOTE: scan sizec during zombie flushing
|
1615
1617
|
# (flush_zombies) individual redis config
|
1616
|
-
config
|
1617
|
-
config
|
1618
|
-
config
|
1619
|
-
config
|
1618
|
+
config['swarm.flush_zombies.redis_config.sentinel'] = false # NOTE: individual redis config
|
1619
|
+
config['swarm.flush_zombies.redis_config.pooled'] = false # NOTE: individual redis config
|
1620
|
+
config['swarm.flush_zombies.redis_config.config'] = {} # NOTE: individual redis config
|
1621
|
+
config['swarm.flush_zombies.redis_config.pool_config'] = {} # NOTE: individual redis config
|
1620
1622
|
end
|
1621
1623
|
```
|
1622
1624
|
</details>
|
@@ -1688,7 +1690,7 @@ rql.possible_host_ids
|
|
1688
1690
|
:zombie_locks=>#<Set: {"rql:lock:kekpek"}>}
|
1689
1691
|
[5] pry(main)> rql.zombie_locks
|
1690
1692
|
=> #<Set: {"rql:lock:kekpek"}>
|
1691
|
-
[6] pry(main)> rql.
|
1693
|
+
[6] pry(main)> rql.zombie_acquirers
|
1692
1694
|
=> #<Set: {"rql:acq:17580/2260/2380/2280/3f16b93973612580"}>
|
1693
1695
|
[7] pry(main)> rql.zombie_hosts
|
1694
1696
|
=> #<Set:
|
@@ -1730,7 +1732,7 @@ rql.possible_host_ids
|
|
1730
1732
|
:flush_zombies=>{:enabled=>true, :ractor=>{:running=>true, :state=>"running"}, :main_loop=>{:running=>true, :state=>"sleep"}}}
|
1731
1733
|
[11] pry(main)> rql.zombies_info
|
1732
1734
|
=> {:zombie_hosts=>#<Set: {}>, :zombie_acquirers=>#<Set: {}>, :zombie_locks=>#<Set: {}>}
|
1733
|
-
[12] pry(main)> rql.
|
1735
|
+
[12] pry(main)> rql.zombie_acquirers
|
1734
1736
|
=> #<Set: {}>
|
1735
1737
|
[13] pry(main)> rql.zombie_hosts
|
1736
1738
|
=> #<Set: {}>
|
@@ -1761,7 +1763,7 @@ rql.possible_host_ids
|
|
1761
1763
|
- `:queued` (FIFO): the classic queued behavior (default), your lock will be obitaned if you are first in queue and the required lock is free;
|
1762
1764
|
- `:random` (RANDOM): obtain a lock without checking the positions in the queue (but with checking the limist, retries, timeouts and so on). if lock is free to obtain - it will be obtained;
|
1763
1765
|
- for current implementation detalis check:
|
1764
|
-
- [Configuration](#configuration) documentation: see `config
|
1766
|
+
- [Configuration](#configuration) documentation: see `config['default_access_strategy']` config docs;
|
1765
1767
|
- [#lock](#lock---obtain-a-lock) method documentation: see `access_strategy` attribute docs;
|
1766
1768
|
|
1767
1769
|
---
|
@@ -1779,7 +1781,7 @@ rql.possible_host_ids
|
|
1779
1781
|
"is your lock are obtained or not" is made as you work with **reentrant locks** (your process continues to use the lock without/with
|
1780
1782
|
lock's TTL extension accordingly);
|
1781
1783
|
- for current implementation details check:
|
1782
|
-
- [Configuration](#configuration) documentation: see `config
|
1784
|
+
- [Configuration](#configuration) documentation: see `config['default_conflict_strategy']` config docs;
|
1783
1785
|
- [#lock](#lock---obtain-a-lock) method documentation: see `conflict_strategy` attribute docs and the method result data;
|
1784
1786
|
|
1785
1787
|
---
|
@@ -1796,7 +1798,7 @@ rql.possible_host_ids
|
|
1796
1798
|
```ruby
|
1797
1799
|
"[redis_queued_locks.start_lock_obtaining]" # (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
|
1798
1800
|
"[redis_queued_locks.start_try_to_lock_cycle]" # (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
|
1799
|
-
"[redis_queued_locks.
|
1801
|
+
"[redis_queued_locks.dead_score_reached__reset_acquirer_position]" # (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
|
1800
1802
|
"[redis_queued_locks.lock_obtained]" # (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acq_time");
|
1801
1803
|
"[redis_queued_locks.extendable_reentrant_lock_obtained]" # (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat", "acq_time");
|
1802
1804
|
"[redis_queued_locks.reentrant_lock_obtained]" # (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat", "acq_time");
|
@@ -1831,8 +1833,8 @@ rql.possible_host_ids
|
|
1831
1833
|
<sup>\[[back to top](#table-of-contents)\]</sup>
|
1832
1834
|
|
1833
1835
|
**NOTICE**: logging can be sampled via:
|
1834
|
-
- `config
|
1835
|
-
- `config
|
1836
|
+
- `config['log_samplign_enabled'] = true` (**false** by default);
|
1837
|
+
- `config['log_sampler'] = RedisQueuedLocks::Logging::Sampler` (used by default);
|
1836
1838
|
- see **RedisQueuedLocks::Logging::Sampler** implementation in source code for customization details;
|
1837
1839
|
|
1838
1840
|
```ruby
|
@@ -1843,7 +1845,7 @@ rql.possible_host_ids
|
|
1843
1845
|
# - at this moment the only debug logs are realised in following cases:
|
1844
1846
|
# - "[redis_queued_locks.start_lock_obtaining]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
|
1845
1847
|
# - "[redis_queued_locks.start_try_to_lock_cycle]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
|
1846
|
-
# - "[redis_queued_locks.
|
1848
|
+
# - "[redis_queued_locks.dead_score_reached__reset_acquirer_position]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
|
1847
1849
|
# - "[redis_queued_locks.lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acq_time", "acs_strat");
|
1848
1850
|
# - "[redis_queued_locks.extendable_reentrant_lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acq_time", "acs_strat");
|
1849
1851
|
# - "[redis_queued_locks.reentrant_lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acq_time", "acs_strat");
|
@@ -1851,7 +1853,7 @@ rql.possible_host_ids
|
|
1851
1853
|
# - "[redis_queued_locks.expire_lock]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
|
1852
1854
|
# - "[redis_queued_locks.decrease_lock]" (logs "lock_key", "decreased_ttl", "queue_ttl", "acq_id", "hst_id", "acs_strat");
|
1853
1855
|
# - by default uses VoidLogger that does nothing;
|
1854
|
-
config
|
1856
|
+
config['logger'] = RedisQueuedLocks::Logging::VoidLogger
|
1855
1857
|
|
1856
1858
|
# (default: false)
|
1857
1859
|
# - adds additional debug logs;
|
@@ -1870,28 +1872,28 @@ config.logger = RedisQueuedLocks::Logging::VoidLogger
|
|
1870
1872
|
# - "[redis_queued_locks.try_lock.exit__no_first]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat", "first_acq_id_in_queue", "<current_lock_data>");
|
1871
1873
|
# - "[redis_queued_locks.try_lock.exit__lock_still_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat", "first_acq_id_in_queue", "locked_by_acq_id", "<current_lock_data>");
|
1872
1874
|
# - "[redis_queued_locks.try_lock.obtain__free_to_acquire]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
|
1873
|
-
config
|
1875
|
+
config['log_lock_try'] = false
|
1874
1876
|
|
1875
1877
|
# (default: false)
|
1876
1878
|
# - enables <log sampling>: only the configured percent of RQL cases will be logged;
|
1877
1879
|
# - disabled by default;
|
1878
|
-
# - works in tandem with <config
|
1879
|
-
config
|
1880
|
+
# - works in tandem with <config['log_sampling_percent']> and <config['log_sampler']> configs;
|
1881
|
+
config['log_sampling_enabled'] = false
|
1880
1882
|
|
1881
1883
|
# (default: 15)
|
1882
1884
|
# - the percent of cases that should be logged;
|
1883
|
-
# - take an effect when <config
|
1884
|
-
# - works in tandem with <config
|
1885
|
-
config
|
1885
|
+
# - take an effect when <config['log_sampling_enalbed']> is true;
|
1886
|
+
# - works in tandem with <config['log_sampling_enabled']> and <config['log_sampler']> configs;
|
1887
|
+
config['log_sampling_percent'] = 15
|
1886
1888
|
|
1887
1889
|
# (default: RedisQueuedLocks::Logging::Sampler)
|
1888
1890
|
# - percent-based log sampler that decides should be RQL case logged or not;
|
1889
|
-
# - works in tandem with <config
|
1891
|
+
# - works in tandem with <config['log_sampling_enabled']> and <config['log_sampling_percent']> configs;
|
1890
1892
|
# - based on the ultra simple percent-based (weight-based) algorithm that uses SecureRandom.rand
|
1891
1893
|
# method so the algorithm error is ~(0%..13%);
|
1892
1894
|
# - you can provide your own log sampler with bettter algorithm that should realize
|
1893
1895
|
# `sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Logging::Sampler` for example);
|
1894
|
-
config
|
1896
|
+
config['log_sampler'] = RedisQueuedLocks::Logging::Sampler
|
1895
1897
|
```
|
1896
1898
|
|
1897
1899
|
---
|
@@ -1903,7 +1905,7 @@ config.log_sampler = RedisQueuedLocks::Logging::Sampler
|
|
1903
1905
|
- [Instrumentation Events](#instrumentation-events)
|
1904
1906
|
- [Instrumentation Configuration](#instrumentation-configuration)
|
1905
1907
|
|
1906
|
-
An instrumentation layer is incapsulated in `instrumenter` object stored in [config](#configuration) (`RedisQueuedLocks::Client#config[
|
1908
|
+
An instrumentation layer is incapsulated in `instrumenter` object stored in [config](#configuration) (`RedisQueuedLocks::Client#config['instrumenter']`).
|
1907
1909
|
|
1908
1910
|
Instrumentation can be sampled. See [Instrumentation Configuration](#instrumentation-configuration) section for details.
|
1909
1911
|
|
@@ -1927,8 +1929,8 @@ By default `RedisQueuedLocks::Client` is configured with the void notifier (whic
|
|
1927
1929
|
<sup>\[[back to top](#table-of-contents)\]</sup>
|
1928
1930
|
|
1929
1931
|
**NOTICE**: instrumentation can be sampled via:
|
1930
|
-
- `config
|
1931
|
-
- `config
|
1932
|
+
- `config['instr_sampling_enabled'] = true` (**false** by default);
|
1933
|
+
- `config['instr_sampler'] = RedisQueuedLocks::Instrument::Sampler` (used by default);
|
1932
1934
|
- see **RedisQueuedLocks::Instrument::Sampler** implementation in source code for customization details;
|
1933
1935
|
|
1934
1936
|
```ruby
|
@@ -1938,28 +1940,28 @@ By default `RedisQueuedLocks::Client` is configured with the void notifier (whic
|
|
1938
1940
|
# - event: <string> requried;
|
1939
1941
|
# - payload: <hash> requried;
|
1940
1942
|
# - disabled by default via `VoidNotifier`;
|
1941
|
-
config
|
1943
|
+
config['instrumenter'] = RedisQueuedLocks::Instrument::ActiveSupport
|
1942
1944
|
|
1943
1945
|
# (default: false)
|
1944
1946
|
# - enables <instrumentaion sampling>: only the configured percent of RQL cases will be instrumented;
|
1945
1947
|
# - disabled by default;
|
1946
|
-
# - works in tandem with <config
|
1947
|
-
config
|
1948
|
+
# - works in tandem with <config['instr_sampling_percent']> and <config['instr_sampler']>;
|
1949
|
+
config['instr_sampling_enabled'] = false
|
1948
1950
|
|
1949
1951
|
# (default: 15)
|
1950
1952
|
# - the percent of cases that should be instrumented;
|
1951
|
-
# - take an effect when <config
|
1952
|
-
# - works in tandem with <config
|
1953
|
-
config
|
1953
|
+
# - take an effect when <config['instr_sampling_enalbed']> is true;
|
1954
|
+
# - works in tandem with <config['instr_sampling_enabled']> and <config['instr_sampler']> configs;
|
1955
|
+
config['instr_sampling_percent'] = 15
|
1954
1956
|
|
1955
1957
|
# (default: RedisQueuedLocks::Instrument::Sampler)
|
1956
1958
|
# - percent-based log sampler that decides should be RQL case instrumented or not;
|
1957
|
-
# - works in tandem with <config
|
1959
|
+
# - works in tandem with <config['instr_sampling_enabled']> and <config['instr_sampling_percent']> configs;
|
1958
1960
|
# - based on the ultra simple percent-based (weight-based) algorithm that uses SecureRandom.rand
|
1959
1961
|
# method so the algorithm error is ~(0%..13%);
|
1960
1962
|
# - you can provide your own log sampler with bettter algorithm that should realize
|
1961
1963
|
# `sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Instrument::Sampler` for example);
|
1962
|
-
config
|
1964
|
+
config['instr_sampler'] = RedisQueuedLocks::Instrument::Sampler
|
1963
1965
|
```
|
1964
1966
|
|
1965
1967
|
---
|
@@ -1985,7 +1987,7 @@ Detalized event semantics and payload structure:
|
|
1985
1987
|
- raised from `#lock`/`#lock!`;
|
1986
1988
|
- payload:
|
1987
1989
|
- `:ttl` - `integer`/`milliseconds` - lock ttl;
|
1988
|
-
- `:acq_id` - `string` - lock
|
1990
|
+
- `:acq_id` - `string` - lock acquirer identifier;
|
1989
1991
|
- `:hst_id` - `string` - lock's host identifier;
|
1990
1992
|
- `:lock_key` - `string` - lock name;
|
1991
1993
|
- `:ts` - `numeric`/`epoch` - the time when the lock was obtaiend;
|
@@ -1998,7 +2000,7 @@ Detalized event semantics and payload structure:
|
|
1998
2000
|
- payload:
|
1999
2001
|
- `:lock_key` - `string` - lock name;
|
2000
2002
|
- `:ttl` - `integer`/`milliseconds` - last lock ttl by reentrant locking;
|
2001
|
-
- `:acq_id` - `string` - lock
|
2003
|
+
- `:acq_id` - `string` - lock acquirer identifier;
|
2002
2004
|
- `:hst_id` - `string` - lock's host identifier;
|
2003
2005
|
- `:ts` - `numeric`/`epoch` - the time when the lock was obtaiend as extendable reentrant lock;
|
2004
2006
|
- `:acq_time` - `float`/`milliseconds` - time spent on lock acquiring;
|
@@ -2010,7 +2012,7 @@ Detalized event semantics and payload structure:
|
|
2010
2012
|
- payload:
|
2011
2013
|
- `:lock_key` - `string` - lock name;
|
2012
2014
|
- `:ttl` - `integer`/`milliseconds` - last lock ttl by reentrant locking;
|
2013
|
-
- `:acq_id` - `string` - lock
|
2015
|
+
- `:acq_id` - `string` - lock acquirer identifier;
|
2014
2016
|
- `:hst_id` - `string` - lock's host identifier;
|
2015
2017
|
- `:ts` - `numeric`/`epoch` - the time when the lock was obtaiend as reentrant lock;
|
2016
2018
|
- `:acq_time` - `float`/`milliseconds` - time spent on lock acquiring;
|
@@ -2022,7 +2024,7 @@ Detalized event semantics and payload structure:
|
|
2022
2024
|
- payload:
|
2023
2025
|
- `:hold_time` - `float`/`milliseconds` - lock hold time;
|
2024
2026
|
- `:ttl` - `integer`/`milliseconds` - lock ttl;
|
2025
|
-
- `:acq_id` - `string` - lock
|
2027
|
+
- `:acq_id` - `string` - lock acquirer identifier;
|
2026
2028
|
- `:hst_id` - `string` - lock's host identifier;
|
2027
2029
|
- `:lock_key` - `string` - lock name;
|
2028
2030
|
- `:ts` - `numeric`/`epoch` - the time when lock was obtained;
|
@@ -2036,7 +2038,7 @@ Detalized event semantics and payload structure:
|
|
2036
2038
|
- payload:
|
2037
2039
|
- `:hold_time` - `float`/`milliseconds` - lock hold time;
|
2038
2040
|
- `:ttl` - `integer`/`milliseconds` - last lock ttl by reentrant locking;
|
2039
|
-
- `:acq_id` - `string` - lock
|
2041
|
+
- `:acq_id` - `string` - lock acquirer identifier;
|
2040
2042
|
- `:hst_id` - `string` - lock's host identifier;
|
2041
2043
|
- `:ts` - `numeric`/`epoch` - the time when the lock was obtaiend as reentrant lock;
|
2042
2044
|
- `:lock_key` - `string` - lock name;
|
@@ -2073,26 +2075,52 @@ Detalized event semantics and payload structure:
|
|
2073
2075
|
trying to ressurect unexpectedly terminated swarm elements, and will notify about this;
|
2074
2076
|
- swarm logs (thread/ractor has some limitations so the initial implementation does not include swarm logging);
|
2075
2077
|
- swarm instrumentation (thread/ractor has some limitations so the initial implementation does not include swarm instrumentation);
|
2078
|
+
- isolated timeouts which are independent of internal Ruby's timeout implementation (where all timeouts are hostend inside
|
2079
|
+
the global "timeout request" queue and managed by a single global "timeout wathcer" thread). it should prevent any logic and timeout intersections,
|
2080
|
+
some GVL-related things and problem situations when the global watcher thread is "dead";
|
2076
2081
|
- lock request prioritization;
|
2077
|
-
- **strict redlock algorithm support** (support for many `RedisClient` instances);
|
2082
|
+
- **strict redlock algorithm support** (support for many `RedisClient` instances that are fully independent (distributed redis instances));
|
2078
2083
|
- `#lock_series` - acquire a series of locks:
|
2079
2084
|
```ruby
|
2080
2085
|
rql.lock_series('lock_a', 'lock_b', 'lock_c') { puts 'locked' }
|
2081
2086
|
```
|
2082
|
-
-
|
2087
|
+
- an ability to release all locks and all requests of the concrete acquirer id or host id (or both in validation-orianted combination);
|
2088
|
+
- detailed lock informotion inside the error object in cases of exceptions (at the moment we have this info inside the error message only that hard to analyze in work);
|
2089
|
+
- a convenient way to mark any `lock` invocation as "non-instrumentable" / "non-loggable" (as an alternative to `VoidNotifier` and to `VoidLogger`);
|
2090
|
+
- `Read`/`Write` semantics: you can mark your locks as `read` or `write` lock in order to simulate `read`/`write` lock behavior:
|
2091
|
+
- `read` - watis - `write`;
|
2092
|
+
- `read` - not waits - `read`;
|
2093
|
+
- `write` - waits - `read`;
|
2094
|
+
- `write` - waits - `write`;
|
2095
|
+
- **write** mode is a default behavior for all RQL locks;
|
2083
2096
|
- **Minor**:
|
2097
|
+
- `#lock`/`#lock!` - `timeout:` option: support for granular periods (it supports only `seconds` at the moment, but we need `milliseconds`);
|
2098
|
+
- Add `after timeout hook` ability for timeout errors with an ability to access the binding context (if it possibly) of the thread where it failed;
|
2099
|
+
- Add `ignore timeout errors` ability (for debug purposes);
|
2100
|
+
- A special explicit documentation section that will explain and clarify which exceptions can be occured and what cases occurs them (at the moment such cases are explained inside the lock methods documentation that is not really convinient);
|
2101
|
+
- Renaming of some exceptions (such as `RedisQueuedLocks::TimedLockTimeoutError`) to make the related problem more quickly, faster and easier to understand;
|
2102
|
+
- Support for detailed `OpenTelemetry` tracing;
|
2103
|
+
- `light mode`: an ability to work without any debug and instrumentation logic and data (totally reduced debugging and instrumenting possibilities, but better performance);
|
2104
|
+
- support for `Dragonfly` database backend (https://github.com/dragonflydb/dragonfly) (https://www.dragonflydb.io/);
|
2105
|
+
- (_research_) GVL-isolation for lock acquirement logic (try to bypass Ruby's "context-switching" in order to prevent any time-based affects on lock-acquirement logic);
|
2084
2106
|
- Semantic error objects for unexpected Redis errors;
|
2085
2107
|
- **Experimental feature**: (non-`timed` locks): per-ruby-block-holding-the-lock sidecar `Ractor` and `in progress queue` in RedisDB that will extend
|
2086
2108
|
the acquired lock for long-running blocks of code (that invoked "under" the lock
|
2087
2109
|
whose ttl may expire before the block execution completes). It makes sense for non-`timed` locks *only*;
|
2110
|
+
- sized lock queues (with an ability of dynamically growing size);
|
2088
2111
|
- better code stylization (+ some refactorings);
|
2089
|
-
- `RedisQueuedLocks::
|
2112
|
+
- `RedisQueuedLocks::Acquirer::Try.try_to_lock` - detailed successful result analization;
|
2090
2113
|
- Support for LIFO strategy;
|
2091
2114
|
- better specs with 100% test coverage (total specs rework);
|
2092
2115
|
- statistics with UI;
|
2093
2116
|
- JSON log formatter;
|
2117
|
+
- **automatic** deadlock detection;
|
2094
2118
|
- `go`-lang implementation;
|
2095
|
-
|
2119
|
+
- (_research_) simplification and speedup of the internal "redis-communuication-and-data-storing"-based algorithms;
|
2120
|
+
- `unlock_on:`-option in lock/lock! logic in order to support auto-unlocking on any exception rasaied under the invoked block (invoked under the lock);
|
2121
|
+
- **Research**: support for `Valkey` database backend (https://github.com/valkey-io/valkey) (https://valkey.io/);
|
2122
|
+
- **Research**: support for `Garnet` database backend (https://microsoft.github.io/) (https://github.com/microsoft/garnet);
|
2123
|
+
- add a library-level exception, when RQL-related key (required for it's logic) has incompatible type (means: some other program uses our key with their own type and logic and RQL can't work properly);
|
2096
2124
|
---
|
2097
2125
|
|
2098
2126
|
## Contributing
|