redis_queued_locks 1.12.1 → 1.14.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.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -1
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +45 -5
  5. data/LICENSE.txt +1 -1
  6. data/README.md +574 -296
  7. data/Rakefile +12 -4
  8. data/Steepfile +15 -0
  9. data/github_ci/ruby3.3.gemfile +17 -0
  10. data/github_ci/ruby3.3.gemfile.lock +217 -0
  11. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/delay_execution.rb +4 -4
  12. data/lib/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +40 -0
  13. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/dequeue_from_lock_queue.rb +17 -8
  14. data/lib/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rb +166 -0
  15. data/lib/redis_queued_locks/acquirer/acquire_lock/log_visitor.rb +218 -0
  16. data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rb +543 -0
  17. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/try_to_lock.rb +126 -92
  18. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/with_acq_timeout.rb +14 -9
  19. data/lib/redis_queued_locks/acquirer/acquire_lock/yield_expire/log_visitor.rb +76 -0
  20. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/yield_expire.rb +42 -19
  21. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock.rb +74 -47
  22. data/lib/redis_queued_locks/{acquier → acquirer}/clear_dead_requests.rb +5 -3
  23. data/lib/redis_queued_locks/{acquier → acquirer}/extend_lock_ttl.rb +4 -3
  24. data/lib/redis_queued_locks/{acquier → acquirer}/is_locked.rb +1 -1
  25. data/lib/redis_queued_locks/{acquier → acquirer}/is_queued.rb +1 -1
  26. data/lib/redis_queued_locks/{acquier → acquirer}/keys.rb +5 -5
  27. data/lib/redis_queued_locks/{acquier → acquirer}/lock_info.rb +9 -5
  28. data/lib/redis_queued_locks/{acquier → acquirer}/locks.rb +16 -3
  29. data/lib/redis_queued_locks/{acquier → acquirer}/queue_info.rb +8 -6
  30. data/lib/redis_queued_locks/{acquier → acquirer}/queues.rb +9 -2
  31. data/lib/redis_queued_locks/{acquier → acquirer}/release_all_locks.rb +26 -21
  32. data/lib/redis_queued_locks/{acquier → acquirer}/release_lock.rb +28 -22
  33. data/lib/redis_queued_locks/acquirer/release_locks_of.rb +211 -0
  34. data/lib/redis_queued_locks/acquirer.rb +19 -0
  35. data/lib/redis_queued_locks/client.rb +317 -254
  36. data/lib/redis_queued_locks/config/dsl.rb +94 -0
  37. data/lib/redis_queued_locks/config.rb +236 -0
  38. data/lib/redis_queued_locks/data.rb +2 -0
  39. data/lib/redis_queued_locks/errors.rb +27 -11
  40. data/lib/redis_queued_locks/instrument.rb +11 -4
  41. data/lib/redis_queued_locks/logging/void_logger.rb +38 -1
  42. data/lib/redis_queued_locks/logging.rb +20 -5
  43. data/lib/redis_queued_locks/resource.rb +49 -11
  44. data/lib/redis_queued_locks/swarm/acquirers.rb +17 -16
  45. data/lib/redis_queued_locks/swarm/flush_zombies.rb +26 -25
  46. data/lib/redis_queued_locks/swarm/probe_hosts.rb +20 -19
  47. data/lib/redis_queued_locks/swarm/redis_client_builder.rb +3 -3
  48. data/lib/redis_queued_locks/swarm/supervisor.rb +19 -6
  49. data/lib/redis_queued_locks/swarm/swarm_element/isolated.rb +20 -18
  50. data/lib/redis_queued_locks/swarm/swarm_element/threaded.rb +35 -27
  51. data/lib/redis_queued_locks/swarm/zombie_info.rb +9 -9
  52. data/lib/redis_queued_locks/swarm.rb +20 -41
  53. data/lib/redis_queued_locks/utilities.rb +11 -2
  54. data/lib/redis_queued_locks/version.rb +2 -2
  55. data/lib/redis_queued_locks.rb +2 -3
  56. data/rbs_collection.lock.yaml +28 -0
  57. data/rbs_collection.yaml +17 -0
  58. data/redis_queued_locks.gemspec +22 -23
  59. data/sig/manifest.yml +6 -0
  60. data/sig/redis_queued_locks/acquier.rbs +4 -0
  61. data/sig/redis_queued_locks/acquirer/acquire_lock/delay_execution.rbs +9 -0
  62. data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rbs +21 -0
  63. data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue.rbs +26 -0
  64. data/sig/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rbs +71 -0
  65. data/sig/redis_queued_locks/acquirer/acquire_lock/log_visitor.rbs +72 -0
  66. data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rbs +179 -0
  67. data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rbs +48 -0
  68. data/sig/redis_queued_locks/acquirer/acquire_lock/with_acq_timeout.rbs +19 -0
  69. data/sig/redis_queued_locks/acquirer/acquire_lock/yield_expire.rbs +41 -0
  70. data/sig/redis_queued_locks/acquirer/acquire_lock/yield_with_expire/log_visitor.rbs +32 -0
  71. data/sig/redis_queued_locks/acquirer/acquire_lock.rbs +52 -0
  72. data/sig/redis_queued_locks/acquirer/clear_dead_requests.rbs +28 -0
  73. data/sig/redis_queued_locks/acquirer/extend_lock_ttl.rbs +28 -0
  74. data/sig/redis_queued_locks/acquirer/is_locked.rbs +9 -0
  75. data/sig/redis_queued_locks/acquirer/is_queued.rbs +9 -0
  76. data/sig/redis_queued_locks/acquirer/keys.rbs +10 -0
  77. data/sig/redis_queued_locks/acquirer/lock_info.rbs +10 -0
  78. data/sig/redis_queued_locks/acquirer/locks.rbs +16 -0
  79. data/sig/redis_queued_locks/acquirer/queue_info.rbs +13 -0
  80. data/sig/redis_queued_locks/acquirer/queues.rbs +16 -0
  81. data/sig/redis_queued_locks/acquirer/release_all_locks.rbs +30 -0
  82. data/sig/redis_queued_locks/acquirer/release_lock.rbs +38 -0
  83. data/sig/redis_queued_locks/acquirer/release_locks_of.rbs +46 -0
  84. data/sig/redis_queued_locks/client.rbs +235 -0
  85. data/sig/redis_queued_locks/config/dsl.rbs +26 -0
  86. data/sig/redis_queued_locks/config.rbs +23 -0
  87. data/sig/redis_queued_locks/data.rbs +4 -0
  88. data/sig/redis_queued_locks/debugger/interface.rbs +9 -0
  89. data/sig/redis_queued_locks/debugger.rbs +13 -0
  90. data/sig/redis_queued_locks/errors.rbs +43 -0
  91. data/sig/redis_queued_locks/instrument/active_support.rbs +7 -0
  92. data/sig/redis_queued_locks/instrument/sampler.rbs +9 -0
  93. data/sig/redis_queued_locks/instrument/void_notifier.rbs +7 -0
  94. data/sig/redis_queued_locks/instrument.rbs +15 -0
  95. data/sig/redis_queued_locks/logging/sampler.rbs +9 -0
  96. data/sig/redis_queued_locks/logging/void_logger.rbs +15 -0
  97. data/sig/redis_queued_locks/logging.rbs +15 -0
  98. data/sig/redis_queued_locks/resource.rbs +42 -0
  99. data/sig/redis_queued_locks/swarm/acquirers.rbs +10 -0
  100. data/sig/redis_queued_locks/swarm/flush_zombies.rbs +13 -0
  101. data/sig/redis_queued_locks/swarm/probe_hosts.rbs +13 -0
  102. data/sig/redis_queued_locks/swarm/redis_client_builder.rbs +19 -0
  103. data/sig/redis_queued_locks/swarm/supervisor.rbs +26 -0
  104. data/sig/redis_queued_locks/swarm/swarm_element/isolated.rbs +52 -0
  105. data/sig/redis_queued_locks/swarm/swarm_element/threaded.rbs +61 -0
  106. data/sig/redis_queued_locks/swarm/swarm_element.rbs +8 -0
  107. data/sig/redis_queued_locks/swarm/zombie_info.rbs +24 -0
  108. data/sig/redis_queued_locks/swarm.rbs +41 -0
  109. data/sig/redis_queued_locks/utilities/lock.rbs +10 -0
  110. data/sig/redis_queued_locks/utilities.rbs +12 -0
  111. data/sig/redis_queued_locks/version.rbs +3 -0
  112. data/sig/redis_queued_locks.rbs +14 -0
  113. data/sig/vendor/active_support.rbs +9 -0
  114. data/sig/vendor/redis_client.rbs +39 -0
  115. data/sig/vendor/semantic_logger.rbs +4 -0
  116. metadata +98 -54
  117. data/lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +0 -40
  118. data/lib/redis_queued_locks/acquier/acquire_lock/instr_visitor.rb +0 -166
  119. data/lib/redis_queued_locks/acquier/acquire_lock/log_visitor.rb +0 -216
  120. data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock/log_visitor.rb +0 -541
  121. data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire/log_visitor.rb +0 -76
  122. data/lib/redis_queued_locks/acquier.rb +0 -18
data/README.md CHANGED
@@ -1,8 +1,10 @@
1
- # RedisQueuedLocks · ![Gem Version](https://img.shields.io/gem/v/redis_queued_locks) ![build](https://github.com/0exp/redis_queued_locks/actions/workflows/build.yml/badge.svg??branch=master)
1
+ # RedisQueuedLocks · ![Gem Version](https://img.shields.io/gem/v/redis_queued_locks)
2
2
 
3
- <a href="https://redis.io/docs/manual/patterns/distributed-locks/">Distributed locks</a> with "prioritized lock acquisition queue" capabilities based on the Redis Database.
3
+ [![Tests (RSpec)](https://github.com/0exp/redis_queued_locks/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/0exp/redis_queued_locks/actions) [![Lint (Rubocop)](https://github.com/0exp/redis_queued_locks/actions/workflows/lint.yml/badge.svg?branch=master)](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)
4
4
 
5
- Each lock request is put into the request queue (each lock is hosted by it's own queue separately from other queues) and processed in order of their priority (FIFO). Each lock request lives some period of time (RTTL) (with requeue capabilities) which guarantees the request queue will never be stacked.
5
+ <a href="https://redis.io/docs/latest/develop/clients/patterns/distributed-locks/">Distributed locks</a> with "prioritized lock acquisition queue" capabilities based on the Redis Database.
6
+
7
+ Each lock request is put into the request queue (each lock is hosted by its own queue separately from other queues) and processed in order of their priority (FIFO). Each lock request lives some period of time (RTTL) (with requeue capabilities) which guarantees the request queue will never be stacked.
6
8
 
7
9
  In addition to the classic `queued` (FIFO) strategy RQL supports `random` (RANDOM) lock obtaining strategy when any acquirer from the lock queue can obtain the lock regardless the position in the queue.
8
10
 
@@ -25,8 +27,10 @@ Provides flexible invocation flow, parametrized limits (lock request ttl, lock t
25
27
  - [queue_info](#queue_info)
26
28
  - [locked?](#locked)
27
29
  - [queued?](#queued)
28
- - [unlock](#unlock---release-a-lock)
29
- - [clear_locks](#clear_locks---release-all-locks-and-lock-queues)
30
+ - [unlock](#unlock---release-a-lock) (aka `release_lock`)
31
+ - [clear_locks](#clear_locks---release-all-locks-and-lock-queues) (aka `release_locks`)
32
+ - [clear_locks_of](#clear_locks_of) (aka `release_locks_of`)
33
+ - [clear_current_locks](#clear_current_locks) (aka `release_current_locks`)
30
34
  - [extend_lock_ttl](#extend_lock_ttl)
31
35
  - [locks](#locks---get-list-of-obtained-locks)
32
36
  - [queues](#queues---get-list-of-lock-request-queues)
@@ -50,7 +54,7 @@ Provides flexible invocation flow, parametrized limits (lock request ttl, lock t
50
54
  - [zombies_info](#zombies_info)
51
55
  - [zombie_locks](#zombie_locks)
52
56
  - [zombie_hosts](#zombie_hosts)
53
- - [zombie_acquiers](#zombie_acquiers)
57
+ - [zombie_acquirers](#zombie_acquirers)
54
58
  - [Lock Access Strategies](#lock-access-strategies)
55
59
  - [queued](#lock-access-strategies)
56
60
  - [random](#lock-access-strategies)
@@ -60,7 +64,16 @@ Provides flexible invocation flow, parametrized limits (lock request ttl, lock t
60
64
  - [Instrumentation](#instrumentation)
61
65
  - [Instrumentation Configuration](#instrumentation-configuration)
62
66
  - [Instrumentation Events](#instrumentation-events)
67
+ - ["redis_queued_locks.lock_obtained"](#redis_queued_lockslock_hold_and_release)
68
+ - ["redis_queued_locks.extendable_reentrant_lock_obtained"](#redis_queued_locksextendable_reentrant_lock_obtained)
69
+ - ["redis_queued_locks.reentrant_lock_obtained"](#redis_queued_locksreentrant_lock_obtained)
70
+ - ["redis_queued_locks.lock_hold_and_release"](#redis_queued_lockslock_hold_and_release)
71
+ - ["redis_queued_locks.reentrant_lock_hold_completes"](#redis_queued_locksreentrant_lock_hold_completes)
72
+ - ["redis_queued_locks.explicit_lock_release"](#redis_queued_locksexplicit_lock_release)
73
+ - ["redis_queued_locks.explicit_all_locks_release"](#redis_queued_locksexplicit_all_locks_release)
74
+ - ["redis_queued_locks.release_locks_of"](#redis_queued_locksrelease_locks_of)
63
75
  - [Roadmap](#roadmap)
76
+ - [Build and Develop](#build-and-develop)
64
77
  - [Contributing](#contributing)
65
78
  - [License](#license)
66
79
  - [Authors](#authors)
@@ -149,32 +162,32 @@ rq_lock_client.lock("some-lock") { puts "Hello, lock!" }
149
162
  ```ruby
150
163
  redis_client = RedisClient.config.new_pool # NOTE: provide your own RedisClient instance
151
164
 
152
- clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
165
+ client = RedisQueuedLocks::Client.new(redis_client) do |config|
153
166
  # (default: 3) (supports nil)
154
167
  # - nil means "infinite retries" and you are only limited by the "try_to_lock_timeout" config;
155
- config.retry_count = 3
168
+ config['retry_count'] = 3
156
169
 
157
170
  # (milliseconds) (default: 200)
158
- config.retry_delay = 200
171
+ config['retry_delay'] = 200
159
172
 
160
173
  # (milliseconds) (default: 25)
161
- config.retry_jitter = 25
174
+ config['retry_jitter'] = 25
162
175
 
163
176
  # (seconds) (supports nil)
164
177
  # - nil means "no timeout" and you are only limited by "retry_count" config;
165
- config.try_to_lock_timeout = 10
178
+ config['try_to_lock_timeout'] = 10
166
179
 
167
180
  # (milliseconds) (default: 5_000)
168
181
  # - lock's time to live
169
- config.default_lock_ttl = 5_000
182
+ config['default_lock_ttl'] = 5_000
170
183
 
171
184
  # (seconds) (default: 15)
172
185
  # - 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.default_queue_ttl = 15
186
+ config['default_queue_ttl'] = 15
174
187
 
175
188
  # (boolean) (default: false)
176
189
  # - should be all blocks of code are timed by default;
177
- config.is_timed_by_default = false
190
+ config['is_timed_by_default'] = false
178
191
 
179
192
  # (boolean) (default: false)
180
193
  # - When the lock acquirement try reached the acquirement time limit (:timeout option) the
@@ -197,7 +210,7 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
197
210
  # and moved from the lock queue after the error moment and before the error message build;
198
211
  # - You should consider the async nature of this error message and should use received data
199
212
  # from error message correspondingly;
200
- config.detailed_acq_timeout_error = false
213
+ config['detailed_acq_timeout_error'] = false
201
214
 
202
215
  # (symbol) (default: :queued)
203
216
  # - Defines the way in which the lock should be obitained;
@@ -208,7 +221,7 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
208
221
  # - `: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
222
  # - `:random` (RANDOM): obtain a lock without checking the positions in the queue (but with checking the limist,
210
223
  # retries, timeouts and so on). if lock is free to obtain - it will be obtained;
211
- config.default_access_strategy = :queued
224
+ config['default_access_strategy'] = :queued
212
225
 
213
226
  # (symbol) (default: :wait_for_lock)
214
227
  # - Global default conflict strategy mode;
@@ -221,24 +234,35 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
221
234
  # - `:extendable_work_through` - continue working under the lock <with> lock's TTL extension;
222
235
  # - `:wait_for_lock` - (default) - work in classic way (with timeouts, retry delays, retry limits, etc - in classic way :));
223
236
  # - `:dead_locking` - fail with deadlock exception;
224
- # - See "Dead locks and Reentrant Locks" documentation section in REDME.md for details;
225
- config.default_conflict_strategy = :wait_for_lock
237
+ # - See "Dead locks and Reentrant Locks" documentation section in README.md for details;
238
+ config['default_conflict_strategy'] = :wait_for_lock
226
239
 
227
240
  # (default: 100)
228
241
  # - how many items will be released at a time in #clear_locks and in #clear_dead_requests (uses SCAN);
229
242
  # - affects the performance of your Redis and Ruby Application (configure thoughtfully);
230
- config.lock_release_batch_size = 100
243
+ config['lock_release_batch_size'] = 100
244
+
245
+ # (default: 300)
246
+ # - how many items will be released at a time in #clear_locks_of and in #clear_current_locks methods (uses SCAN for batch extraction and DEL for batch deletion);
247
+ # - affects the ruby's memory (cuz this batch will be stored in Set object in first, and then will be splatted to the DEL redis method invocation) (configure thoughtfully);
248
+ # - affects the performance of your Redis (configure thoughtfully);
249
+ config['clear_locks_of__lock_scan_size'] = 300
250
+
251
+ # (default: 300)
252
+ # - how many queues will be SCAN'ned at a time in #clear_locks_of and in #clear_current_locks methods (uses SCAN);
253
+ # - affects the performance of your Redis (configure thoughtfully);
254
+ config['clear_locks_of__queue_scan_size'] = 300
231
255
 
232
256
  # (default: 500)
233
257
  # - how many items should be extracted from redis during the #locks, #queues, #keys
234
258
  # #locks_info, and #queues_info operations (uses SCAN);
235
- # - affects the performance of your Redis and Ruby Application (configure thoughtfully;)
236
- config.key_extraction_batch_size = 500
259
+ # - affects the performance of your Redis and Ruby Application (configure thoughtfully);
260
+ config['key_extraction_batch_size'] = 500
237
261
 
238
262
  # (default: 1 day)
239
263
  # - the default period of time (in milliseconds) after which a lock request is considered dead;
240
264
  # - used for `#clear_dead_requests` as default vaule of `:dead_ttl` option;
241
- config.dead_request_ttl = (1 * 24 * 60 * 60 * 1000) # one day in milliseconds
265
+ config['dead_request_ttl'] = (1 * 24 * 60 * 60 * 1000) # one day in milliseconds
242
266
 
243
267
  # (default: RedisQueuedLocks::Instrument::VoidNotifier)
244
268
  # - instrumentation layer;
@@ -246,16 +270,16 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
246
270
  # - event: <string> requried;
247
271
  # - payload: <hash> requried;
248
272
  # - disabled by default via `VoidNotifier`;
249
- config.instrumenter = RedisQueuedLocks::Instrument::ActiveSupport
273
+ config['instrumenter'] = RedisQueuedLocks::Instrument::ActiveSupport
250
274
 
251
275
  # (default: -> { RedisQueuedLocks::Resource.calc_uniq_identity })
252
276
  # - uniqude idenfitier that is uniq per process/pod;
253
277
  # - prevents potential lock-acquirement collisions bettween different process/pods
254
- # that have identical process_id/thread_id/fiber_id/ractor_id (identivcal acquier ids);
278
+ # that have identical process_id/thread_id/fiber_id/ractor_id (identivcal acquirer ids);
255
279
  # - it is calculated once per `RedisQueudLocks::Client` instance;
256
280
  # - expects the proc object;
257
281
  # - `SecureRandom.hex(8)` by default;
258
- config.uniq_identifier = -> { RedisQueuedLocks::Resource.calc_uniq_identity }
282
+ config['uniq_identifier'] = -> { RedisQueuedLocks::Resource.calc_uniq_identity }
259
283
 
260
284
  # (default: RedisQueuedLocks::Logging::VoidLogger)
261
285
  # - the logger object;
@@ -264,7 +288,7 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
264
288
  # - at this moment the only debug logs are realised in following cases:
265
289
  # - "[redis_queued_locks.start_lock_obtaining]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
266
290
  # - "[redis_queued_locks.start_try_to_lock_cycle]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
267
- # - "[redis_queued_locks.dead_score_reached__reset_acquier_position]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
291
+ # - "[redis_queued_locks.dead_score_reached__reset_acquirer_position]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
268
292
  # - "[redis_queued_locks.lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acq_time", "acs_strat");
269
293
  # - "[redis_queued_locks.extendable_reentrant_lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acq_time", "acs_strat");
270
294
  # - "[redis_queued_locks.reentrant_lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acq_time", "acs_strat");
@@ -272,7 +296,7 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
272
296
  # - "[redis_queued_locks.expire_lock]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
273
297
  # - "[redis_queued_locks.decrease_lock]" (logs "lock_key", "decreased_ttl", "queue_ttl", "acq_id", "hst_id", "acs_strat");
274
298
  # - by default uses VoidLogger that does nothing;
275
- config.logger = RedisQueuedLocks::Logging::VoidLogger
299
+ config['logger'] = RedisQueuedLocks::Logging::VoidLogger
276
300
 
277
301
  # (default: false)
278
302
  # - adds additional debug logs;
@@ -291,49 +315,49 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
291
315
  # - "[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
316
  # - "[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
317
  # - "[redis_queued_locks.try_lock.obtain__free_to_acquire]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
294
- config.log_lock_try = false
318
+ config['log_lock_try'] = false
295
319
 
296
320
  # (default: false)
297
321
  # - enables <log sampling>: only the configured percent of RQL cases will be logged;
298
322
  # - disabled by default;
299
- # - works in tandem with <config.log_sampling_percent> and <log.sampler> configs;
300
- config.log_sampling_enabled = false
323
+ # - works in tandem with <config['log_sampling_percent']> and <config['log_sampler']> configs;
324
+ config['log_sampling_enabled'] = false
301
325
 
302
326
  # (default: 15)
303
327
  # - the percent of cases that should be logged;
304
- # - take an effect when <config.log_sampling_enalbed> is true;
305
- # - works in tandem with <config.log_sampling_enabled> and <config.log_sampler> configs;
306
- config.log_sampling_percent = 15
328
+ # - take an effect when <config['log_sampling_enalbed']> is true;
329
+ # - works in tandem with <config['log_sampling_enabled']> and <config['log_sampler']> configs;
330
+ config['log_sampling_percent'] = 15
307
331
 
308
332
  # (default: RedisQueuedLocks::Logging::Sampler)
309
333
  # - percent-based log sampler that decides should be RQL case logged or not;
310
- # - works in tandem with <config.log_sampling_enabled> and <config.log_sampling_percent> configs;
334
+ # - works in tandem with <config['log_sampling_enabled']> and <config['log_sampling_percent']> configs;
311
335
  # - based on the ultra simple percent-based (weight-based) algorithm that uses SecureRandom.rand
312
336
  # method so the algorithm error is ~(0%..13%);
313
337
  # - you can provide your own log sampler with bettter algorithm that should realize
314
338
  # `sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Logging::Sampler` for example);
315
- config.log_sampler = RedisQueuedLocks::Logging::Sampler
339
+ config['log_sampler'] = RedisQueuedLocks::Logging::Sampler
316
340
 
317
341
  # (default: false)
318
342
  # - enables <instrumentaion sampling>: only the configured percent of RQL cases will be instrumented;
319
343
  # - disabled by default;
320
- # - works in tandem with <config.instr_sampling_percent and <log.instr_sampler>;
321
- config.instr_sampling_enabled = false
344
+ # - works in tandem with <config['instr_sampling_percent'] and <config['instr_sampler']>;
345
+ config['nstr_sampling_enabled'] = false
322
346
 
323
347
  # (default: 15)
324
348
  # - the percent of cases that should be instrumented;
325
- # - take an effect when <config.instr_sampling_enalbed> is true;
326
- # - works in tandem with <config.instr_sampling_enabled> and <config.instr_sampler> configs;
327
- config.instr_sampling_percent = 15
349
+ # - take an effect when <config['instr_sampling_enalbed']> is true;
350
+ # - works in tandem with <config['instr_sampling_enabled']> and <config['instr_sampler']> configs;
351
+ config['instr_sampling_percent'] = 15
328
352
 
329
353
  # (default: RedisQueuedLocks::Instrument::Sampler)
330
354
  # - percent-based log sampler that decides should be RQL case instrumented or not;
331
- # - works in tandem with <config.instr_sampling_enabled> and <config.instr_sampling_percent> configs;
355
+ # - works in tandem with <config['instr_sampling_enabled']> and <config['instr_sampling_percent']> configs;
332
356
  # - based on the ultra simple percent-based (weight-based) algorithm that uses SecureRandom.rand
333
357
  # method so the algorithm error is ~(0%..13%);
334
358
  # - you can provide your own log sampler with bettter algorithm that should realize
335
359
  # `sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Instrument::Sampler` for example);
336
- config.instr_sampler = RedisQueuedLocks::Instrument::Sampler
360
+ config['instr_sampler'] = RedisQueuedLocks::Instrument::Sampler
337
361
  end
338
362
  ```
339
363
 
@@ -375,36 +399,36 @@ end
375
399
  - the block's result will be returned;
376
400
  - If block is not passed:
377
401
  - 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, acquier identifier, acquirement timestamp, lock's ttl, type of obtaining process, etc);
402
+ - 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
403
 
380
404
  ```ruby
381
405
  def lock(
382
406
  lock_name,
383
- ttl: config[:default_lock_ttl],
384
- queue_ttl: config[:default_queue_ttl],
385
- timeout: config[:try_to_lock_timeout],
386
- timed: config[:is_timed_by_default],
387
- retry_count: config[:retry_count],
388
- retry_delay: config[:retry_delay],
389
- retry_jitter: config[:retry_jitter],
407
+ ttl: config['default_lock_ttl'],
408
+ queue_ttl: config['default_queue_ttl'],
409
+ timeout: config['try_to_lock_timeout'],
410
+ timed: config['is_timed_by_default'],
411
+ retry_count: config['retry_count'],
412
+ retry_delay: config['retry_delay'],
413
+ retry_jitter: config['retry_jitter'],
390
414
  raise_errors: false,
391
415
  fail_fast: false,
392
- conflict_strategy: config[:default_conflict_strategy],
393
- access_strategy: config[:default_access_strategy],
394
- identity: uniq_identity, # (attr_accessor) calculated during client instantiation via config[:uniq_identifier] proc;
416
+ conflict_strategy: config['default_conflict_strategy'],
417
+ access_strategy: config['default_access_strategy'],
418
+ identity: uniq_identity, # (attr_accessor) calculated during client instantiation via config['uniq_identifier'] proc;
395
419
  meta: nil,
396
- detailed_acq_timeout_error: config[:detailed_acq_timeout_error],
420
+ detailed_acq_timeout_error: config['detailed_acq_timeout_error'],
397
421
  instrument: nil,
398
- instrumenter: config[:instrumenter],
399
- logger: config[:logger],
400
- log_lock_try: config[:log_lock_try],
401
- log_sampling_enabled: config[:log_sampling_enabled],
402
- log_sampling_percent: config[:log_sampling_percent],
403
- log_sampler: config[:log_sampler],
422
+ instrumenter: config['instrumenter'],
423
+ logger: config['logger'],
424
+ log_lock_try: config['log_lock_try'],
425
+ log_sampling_enabled: config['log_sampling_enabled'],
426
+ log_sampling_percent: config['log_sampling_percent'],
427
+ log_sampler: config['log_sampler'],
404
428
  log_sample_this: false,
405
- instr_sampling_enabled: config[:instr_sampling_enabled],
406
- instr_sampling_percent: config[:instr_sampling_percent],
407
- instr_sampler: config[:instr_sampler],
429
+ instr_sampling_enabled: config['instr_sampling_enabled'],
430
+ instr_sampling_percent: config['instr_sampling_percent'],
431
+ instr_sampler: config['instr_sampler'],
408
432
  instr_sample_this: false,
409
433
  &block
410
434
  )
@@ -414,30 +438,30 @@ def lock(
414
438
  - Lock name to be obtained.
415
439
  - `ttl` - (optional) - [Integer]
416
440
  - Lock's time to live (in milliseconds);
417
- - pre-configured in `config[:default_lock_ttl]`;
441
+ - pre-configured in `config['default_lock_ttl']`;
418
442
  - `queue_ttl` - (optional) `[Integer]`
419
443
  - Lifetime of the acuier's lock request. In seconds.
420
- - pre-configured in `config[:default_queue_ttl]`;
444
+ - pre-configured in `config['default_queue_ttl']`;
421
445
  - `timeout` - (optional) `[Integer,NilClass]`
422
446
  - Time period a client should try to acquire the lock (in seconds). Nil means "without timeout".
423
- - pre-configured in `config[:try_to_lock_timeout]`;
447
+ - pre-configured in `config['try_to_lock_timeout']`;
424
448
  - `timed` - (optiona) `[Boolean]`
425
449
  - Limit the invocation time period of the passed block of code by the lock's TTL.
426
- - pre-configured in `config[:is_timed_by_default]`;
450
+ - pre-configured in `config['is_timed_by_default']`;
427
451
  - `false` by default;
428
452
  - `retry_count` - (optional) `[Integer,NilClass]`
429
453
  - How many times we should try to acquire a lock. Nil means "infinite retries".
430
- - pre-configured in `config[:retry_count]`;
454
+ - pre-configured in `config['retry_count']`;
431
455
  - `retry_delay` - (optional) `[Integer]`
432
456
  - A time-interval between the each retry (in milliseconds).
433
- - pre-configured in `config[:retry_delay]`;
457
+ - pre-configured in `config['retry_delay']`;
434
458
  - `retry_jitter` - (optional) `[Integer]`
435
459
  - Time-shift range for retry-delay (in milliseconds);
436
- - pre-configured in `config[:retry_jitter]`;
460
+ - pre-configured in `config['retry_jitter']`;
437
461
  - `instrumenter` - (optional) `[#notify]`
438
462
  - See RedisQueuedLocks::Instrument::ActiveSupport for example;
439
463
  - See [Instrumentation](#instrumentation) section of docs;
440
- - pre-configured in `config[:isntrumenter]` with void notifier (`RedisQueuedLocks::Instrumenter::VoidNotifier`);
464
+ - pre-configured in `config['isntrumenter']` with void notifier (`RedisQueuedLocks::Instrumenter::VoidNotifier`);
441
465
  - `instrument` - (optional) `[NilClass,Any]`
442
466
  - Custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
443
467
  - `nil` by default (means "no custom instrumentation data");
@@ -457,13 +481,13 @@ def lock(
457
481
  - `: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
482
  - `:random` (RANDOM): obtain a lock without checking the positions in the queue (but with checking the limist, retries, timeouts and so on).
459
483
  if lock is free to obtain - it will be obtained;
460
- - pre-configured in `config[:default_access_strategy]`;
484
+ - pre-configured in `config['default_access_strategy']`;
461
485
  - See [Lock Access Strategies](#lock-access-strategies) documentation section for details;
462
486
  - `conflict_strategy` - (optional) - `[Symbol]`
463
487
  - The conflict strategy mode for cases when the process that obtained the lock
464
488
  want to acquire this lock again;
465
489
  - By default uses `:wait_for_lock` strategy;
466
- - pre-confured in `config[:default_conflict_strategy]`;
490
+ - pre-confured in `config['default_conflict_strategy']`;
467
491
  - Strategies:
468
492
  - `:work_through` - continue working under the lock **without** lock's TTL extension;
469
493
  - `:extendable_work_through` - continue working under the lock **with** lock's TTL extension;
@@ -476,7 +500,7 @@ def lock(
476
500
  pods or/and nodes of your application;
477
501
  - It is calculated once during `RedisQueuedLock::Client` instantiation and stored in `@uniq_identity`
478
502
  ivar (accessed via `uniq_dentity` accessor method);
479
- - Identity calculator is pre-configured in `config[:uniq_identifier]`;
503
+ - Identity calculator is pre-configured in `config['uniq_identifier']`;
480
504
  - `meta` - (optional) `[NilClass,Hash<String|Symbol,Any>]`
481
505
  - A custom metadata wich will be passed to the lock data in addition to the existing data;
482
506
  - Custom metadata can not contain reserved lock data keys (such as `lock_key`, `acq_id`, `ts`, `ini_ttl`, `rem_ttl`);
@@ -499,24 +523,24 @@ def lock(
499
523
  and moved from the lock queue after the error moment and before the error message build;
500
524
  - You should consider the async nature of this error message and should use received data
501
525
  from error message correspondingly;
502
- - pre-configred in `config[:detailed_acq_timeout_error]`;
526
+ - pre-configred in `config['detailed_acq_timeout_error']`;
503
527
  - `logger` - (optional) `[::Logger,#debug]`
504
528
  - Logger object used for loggin internal mutation oeprations and opertioan results / process progress;
505
- - pre-configured in `config[:logger]` with void logger `RedisQueuedLocks::Logging::VoidLogger`;
529
+ - pre-configured in `config['logger']` with void logger `RedisQueuedLocks::Logging::VoidLogger`;
506
530
  - `log_lock_try` - (optional) `[Boolean]`
507
531
  - 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[:log_lock_try]`;
532
+ - pre-configured in `config['log_lock_try']`;
509
533
  - `false` by default;
510
534
  - `log_sampling_enabled` - (optional) `[Boolean]`
511
535
  - enables **log sampling**: only the configured percent of RQL cases will be logged;
512
536
  - disabled by default;
513
537
  - works in tandem with `log_sampling_percent` and `log_sampler` options;
514
- - pre-configured in `config[:log_sampling_enabled]`;
538
+ - pre-configured in `config['log_sampling_enabled']`;
515
539
  - `log_sampling_percent` - (optional) `[Integer]`
516
540
  - the percent of cases that should be logged;
517
541
  - take an effect when `log_sampling_enalbed` is true;
518
542
  - works in tandem with `log_sampling_enabled` and `log_sampler` options;
519
- - pre-configured in `config[:log_sampling_percent]`;
543
+ - pre-configured in `config['log_sampling_percent']`;
520
544
  - `log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
521
545
  - percent-based log sampler that decides should be RQL case logged or not;
522
546
  - works in tandem with `log_sampling_enabled` and `log_sampling_percent` options;
@@ -524,7 +548,7 @@ def lock(
524
548
  method so the algorithm error is ~(0%..13%);
525
549
  - you can provide your own log sampler with bettter algorithm that should realize
526
550
  `sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Logging::Sampler` for example);
527
- - pre-configured in `config[:log_sampler]`;
551
+ - pre-configured in `config['log_sampler']`;
528
552
  - `log_sample_this` - (optional) `[Boolean]`
529
553
  - marks the method that everything should be logged despite the enabled log sampling;
530
554
  - makes sense when log sampling is enabled;
@@ -533,12 +557,12 @@ def lock(
533
557
  - enables **instrumentaion sampling**: only the configured percent of RQL cases will be instrumented;
534
558
  - disabled by default;
535
559
  - works in tandem with `instr_sampling_percent` and `instr_sampler` options;
536
- - pre-configured in `config[:instr_sampling_enabled]`;
560
+ - pre-configured in `config['instr_sampling_enabled']`;
537
561
  - `instr_sampling_percent` - (optional) `[Integer]`
538
562
  - the percent of cases that should be instrumented;
539
563
  - take an effect when `instr_sampling_enalbed` is true;
540
564
  - works in tandem with `instr_sampling_enabled` and `instr_sampler` options;
541
- - pre-configured in `config[:instr_sampling_percent]`;
565
+ - pre-configured in `config['instr_sampling_percent']`;
542
566
  - `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
543
567
  - percent-based log sampler that decides should be RQL case instrumented or not;
544
568
  - works in tandem with `instr_sampling_enabled` and `instr_sampling_percent` options;
@@ -546,7 +570,7 @@ def lock(
546
570
  method so the algorithm error is ~(0%..13%);
547
571
  - you can provide your own log sampler with bettter algorithm that should realize
548
572
  `sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Instrument::Sampler` for example);
549
- - pre-configured in `config[:instr_sampler]`;
573
+ - pre-configured in `config['instr_sampler']`;
550
574
  - `instr_sample_this` - (optional) `[Boolean]`
551
575
  - marks the method that everything should be instrumneted despite the enabled instrumentation sampling;
552
576
  - makes sense when instrumentation sampling is enabled;
@@ -594,8 +618,8 @@ Return value:
594
618
  {
595
619
  ok: true,
596
620
  result: {
597
- lock_key: String, # acquierd lock key ("rql:lock:your_lock_name")
598
- acq_id: String, # acquier identifier ("process_id/thread_id/fiber_id/ractor_id/identity")
621
+ lock_key: String, # acquirerd lock key ("rql:lock:your_lock_name")
622
+ acq_id: String, # acquirer identifier ("process_id/thread_id/fiber_id/ractor_id/identity")
599
623
  hst_id: String, # host identifier ("process_id/thread_id/ractor_id/identity")
600
624
  ts: Float, # time (epoch) when lock was obtained (float, Time#to_f)
601
625
  ttl: Integer, # lock's time to live in milliseconds (integer)
@@ -733,7 +757,7 @@ rql.lock("my_lock", queue_ttl: 5, timeout: 10_000, retry_count: nil)
733
757
  ```
734
758
 
735
759
  - obtain a lock in `:random` way (with `:random` strategy): in `:random` strategy
736
- any acquirer from the lcok queue can obtain the lock regardless of the position in the lock queue;
760
+ any acquirer from the lock queue can obtain the lock regardless of the position in the lock queue;
737
761
 
738
762
  ```ruby
739
763
  # Current Process (process#1)
@@ -786,37 +810,37 @@ rql.lock('my_lock', retry_delay: 3000, ttl: 3000, access_strategy: :random)
786
810
  - `#lock!` - exceptional lock obtaining;
787
811
  - fails when (and with):
788
812
  - (`RedisQueuedLocks::LockAlreadyObtainedError`) when `fail_fast` is `true` and lock is already obtained;
789
- - (`RedisQueuedLocks::LockAcquiermentTimeoutError`) `timeout` limit reached before lock is obtained;
790
- - (`RedisQueuedLocks::LockAcquiermentRetryLimitError`) `retry_count` limit reached before lock is obtained;
813
+ - (`RedisQueuedLocks::LockAcquirementTimeoutError`) `timeout` limit reached before lock is obtained;
814
+ - (`RedisQueuedLocks::LockAcquirementRetryLimitError`) `retry_count` limit reached before lock is obtained;
791
815
  - (`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
816
 
793
817
  ```ruby
794
818
  def lock!(
795
819
  lock_name,
796
- ttl: config[:default_lock_ttl],
797
- queue_ttl: config[:default_queue_ttl],
798
- timeout: config[:try_to_lock_timeout],
799
- timed: config[:is_timed_by_default],
800
- retry_count: config[:retry_count],
801
- retry_delay: config[:retry_delay],
802
- retry_jitter: config[:retry_jitter],
820
+ ttl: config['default_lock_ttl'],
821
+ queue_ttl: config['default_queue_ttl'],
822
+ timeout: config['try_to_lock_timeout'],
823
+ timed: config['is_timed_by_default'],
824
+ retry_count: config['retry_count'],
825
+ retry_delay: config['retry_delay'],
826
+ retry_jitter: config['retry_jitter'],
803
827
  fail_fast: false,
804
828
  identity: uniq_identity,
805
829
  meta: nil,
806
- detailed_acq_timeout_error: config[:detailed_acq_timeout_error]
807
- logger: config[:logger],
808
- log_lock_try: config[:log_lock_try],
830
+ detailed_acq_timeout_error: config['detailed_acq_timeout_error']
831
+ logger: config['logger'],
832
+ log_lock_try: config['log_lock_try'],
809
833
  instrument: nil,
810
- instrumenter: config[:instrumenter],
811
- access_strategy: config[:default_access_strategy],
812
- conflict_strategy: config[:default_conflict_strategy],
813
- log_sampling_enabled: config[:log_sampling_enabled],
814
- log_sampling_percent: config[:log_sampling_percent],
815
- log_sampler: config[:log_sampler],
834
+ instrumenter: config['instrumenter'],
835
+ access_strategy: config['default_access_strategy'],
836
+ conflict_strategy: config['default_conflict_strategy'],
837
+ log_sampling_enabled: config['log_sampling_enabled'],
838
+ log_sampling_percent: config['log_sampling_percent'],
839
+ log_sampler: config['log_sampler'],
816
840
  log_sample_this: false,
817
- instr_sampling_enabled: config[:instr_sampling_enabled],
818
- instr_sampling_percent: config[:instr_sampling_percent],
819
- instr_sampler: config[:instr_sampler],
841
+ instr_sampling_enabled: config['instr_sampling_enabled'],
842
+ instr_sampling_percent: config['instr_sampling_percent'],
843
+ instr_sampler: config['instr_sampler'],
820
844
  instr_sample_this: false,
821
845
  &block
822
846
  )
@@ -834,7 +858,7 @@ See `#lock` method [documentation](#lock---obtain-a-lock).
834
858
  - returns `nil` if lock does not exist;
835
859
  - lock data (`Hash<String,String|Integer>`):
836
860
  - `"lock_key"` - `string` - lock key in redis;
837
- - `"acq_id"` - `string` - acquier identifier (process_id/thread_id/fiber_id/ractor_id/identity);
861
+ - `"acq_id"` - `string` - acquirer identifier (process_id/thread_id/fiber_id/ractor_id/identity);
838
862
  - `"hst_id"` - `string` - host identifier (process_id/thread_id/ractor_id/identity);
839
863
  - `"ts"` - `numeric`/`epoch` - the time when lock was obtained;
840
864
  - `"init_ttl"` - `integer` - (milliseconds) initial lock key ttl;
@@ -885,7 +909,7 @@ rql.lock_info("your_lock_name")
885
909
 
886
910
  ```ruby
887
911
  # <for reentrant locks>
888
- # (see `conflict_strategy:` kwarg attribute of #lock/#lock! methods and `config.default_conflict_strategy` config)
912
+ # (see `conflict_strategy:` kwarg attribute of #lock/#lock! methods and `config['default_conflict_strategy']` config)
889
913
 
890
914
  rql.lock("your_lock_name", ttl: 5_000)
891
915
  rql.lock("your_lock_name", ttl: 3_000)
@@ -927,12 +951,12 @@ you can receive the lock queue info with empty queue value (an empty array).
927
951
  - queue represents the ordered set of lock key reqests:
928
952
  - set is ordered by score in ASC manner (inside the Redis Set);
929
953
  - score is represented as a timestamp when the lock request was made;
930
- - represents the acquier identifier and their score as an array of hashes;
954
+ - represents the acquirer identifier and their score as an array of hashes;
931
955
  - returns `nil` if lock queue does not exist;
932
956
  - lock queue data (`Hash<String,String|Array<Hash<String|Numeric>>`):
933
957
  - `"lock_queue"` - `string` - lock queue key in redis;
934
958
  - `"queue"` - `array` - an array of lock requests (array of hashes):
935
- - `"acq_id"` - `string` - acquier identifier (process_id/thread_id/fiber_id/ractor_id/identity by default);
959
+ - `"acq_id"` - `string` - acquirer identifier (process_id/thread_id/fiber_id/ractor_id/identity by default);
936
960
  - `"score"` - `float`/`epoch` - time when the lock request was made (epoch);
937
961
 
938
962
  ```ruby
@@ -987,35 +1011,35 @@ rql.queued?("your_lock_name") # => true/false
987
1011
  - `lock_name` - (required) `[String]` - the lock name that should be released.
988
1012
  - `:logger` - (optional) `[::Logger,#debug]`
989
1013
  - custom logger object;
990
- - pre-configured in `config[:logger]`;
1014
+ - pre-configured in `config['logger']`;
991
1015
  - `:instrumenter` - (optional) `[#notify]`
992
1016
  - custom instrumenter object;
993
- - pre-configured in `config[:instrumetner]`;
1017
+ - pre-configured in `config['instrumetner']`;
994
1018
  - `:instrument` - (optional) `[NilClass,Any]`;
995
1019
  - custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
996
1020
  - `nil` by default (no additional data);
997
1021
  - `:log_sampling_enabled` - (optional) `[Boolean]`
998
1022
  - enables **log sampling**;
999
- - pre-configured in `config[:log_sampling_enabled]`;
1023
+ - pre-configured in `config['log_sampling_enabled']`;
1000
1024
  - `:log_sampling_percent` - (optional) `[Integer]`
1001
1025
  - **log sampling**:the percent of cases that should be logged;
1002
- - pre-configured in `config[:log_sampling_percent]`;
1026
+ - pre-configured in `config['log_sampling_percent']`;
1003
1027
  - `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
1004
1028
  - **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
1005
- - pre-configured in `config[:log_sampler]`;
1029
+ - pre-configured in `config['log_sampler']`;
1006
1030
  - `log_sample_this` - (optional) `[Boolean]`
1007
1031
  - marks the method that everything should be logged despite the enabled log sampling;
1008
1032
  - makes sense when log sampling is enabled;
1009
1033
  - `false` by default;
1010
1034
  - `:instr_sampling_enabled` - (optional) `[Boolean]`
1011
1035
  - enables **instrumentaion sampling**;
1012
- - pre-configured in `config[:instr_sampling_enabled]`;
1036
+ - pre-configured in `config['instr_sampling_enabled']`;
1013
1037
  - `instr_sampling_percent` - (optional) `[Integer]`
1014
1038
  - the percent of cases that should be instrumented;
1015
- - pre-configured in `config[:instr_sampling_percent]`;
1039
+ - pre-configured in `config['instr_sampling_percent']`;
1016
1040
  - `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
1017
1041
  - percent-based log sampler that decides should be RQL case instrumented or not;
1018
- - pre-configured in `config[:instr_sampler]`;
1042
+ - pre-configured in `config['instr_sampler']`;
1019
1043
  - `instr_sample_this` - (optional) `[Boolean]`
1020
1044
  - marks the method that everything should be instrumneted despite the enabled instrumentation sampling;
1021
1045
  - makes sense when instrumentation sampling is enabled;
@@ -1062,37 +1086,37 @@ rql.unlock("your_lock_name")
1062
1086
  - accepts:
1063
1087
  - `:batch_size` - (optional) `[Integer]`
1064
1088
  - 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[:lock_release_batch_size]`;
1089
+ - pre-configured in `config['lock_release_batch_size']`;
1066
1090
  - `:logger` - (optional) `[::Logger,#debug]`
1067
1091
  - custom logger object;
1068
- - pre-configured value in `config[:logger]`;
1092
+ - pre-configured value in `config['logger']`;
1069
1093
  - `:instrumenter` - (optional) `[#notify]`
1070
1094
  - custom instrumenter object;
1071
- - pre-configured value in `config[:isntrumenter]`;
1095
+ - pre-configured value in `config['isntrumenter']`;
1072
1096
  - `:instrument` - (optional) `[NilClass,Any]`
1073
1097
  - custom instrumentation data wich will be passed to the instrumenter's payload with `:instrument` key;
1074
1098
  - `:log_sampling_enabled` - (optional) `[Boolean]`
1075
1099
  - enables **log sampling**;
1076
- - pre-configured in `config[:log_sampling_enabled]`;
1100
+ - pre-configured in `config['log_sampling_enabled']`;
1077
1101
  - `:log_sampling_percent` - (optional) `[Integer]`
1078
1102
  - **log sampling**:the percent of cases that should be logged;
1079
- - pre-configured in `config[:log_sampling_percent]`;
1103
+ - pre-configured in `config['log_sampling_percent']`;
1080
1104
  - `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
1081
1105
  - **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
1082
- - pre-configured in `config[:log_sampler]`;
1106
+ - pre-configured in `config['log_sampler']`;
1083
1107
  - `log_sample_this` - (optional) `[Boolean]`
1084
1108
  - marks the method that everything should be logged despite the enabled log sampling;
1085
1109
  - makes sense when log sampling is enabled;
1086
1110
  - `false` by default;
1087
1111
  - `:instr_sampling_enabled` - (optional) `[Boolean]`
1088
1112
  - enables **instrumentaion sampling**;
1089
- - pre-configured in `config[:instr_sampling_enabled]`;
1113
+ - pre-configured in `config['instr_sampling_enabled']`;
1090
1114
  - `instr_sampling_percent` - (optional) `[Integer]`
1091
1115
  - the percent of cases that should be instrumented;
1092
- - pre-configured in `config[:instr_sampling_percent]`;
1116
+ - pre-configured in `config['instr_sampling_percent']`;
1093
1117
  - `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
1094
1118
  - percent-based log sampler that decides should be RQL case instrumented or not;
1095
- - pre-configured in `config[:instr_sampler]`;
1119
+ - pre-configured in `config['instr_sampler']`;
1096
1120
  - `instr_sample_this` - (optional) `[Boolean]`
1097
1121
  - marks the method that everything should be instrumneted despite the enabled instrumentation sampling;
1098
1122
  - makes sense when instrumentation sampling is enabled;
@@ -1118,6 +1142,197 @@ rql.clear_locks
1118
1142
 
1119
1143
  ---
1120
1144
 
1145
+ #### #clear_locks_of
1146
+
1147
+ <sup>\[[back to top](#usage)\]</sup>
1148
+
1149
+ - release all locks of the passed acquirer/host and remove this acquirer/host from all queues (locks will be released first)
1150
+ - this is a cleanup helper intended for operational and debugging scenarios (for example: your
1151
+ current puma request thread is killed by Rack::Timeout and you need to cleanup all zombie RQL
1152
+ locks and lock reuqests obtained during the request processing);
1153
+ - acquirer/host dentifiers can be extracted via:
1154
+ - `#current_host_id`
1155
+ - `#current_acquirer_id`
1156
+ - `#possible_host_ids`
1157
+ - from lock data (extracted via `#lock_info`, `#locks_info`, `#queue_info`, `#queues_info`);
1158
+ - produces `"redis_queued_locks.release_locks_of"` instrumentation event;
1159
+ - accepts:
1160
+ - `:host_id` - (required) `[String]`
1161
+ - host indentifier whose locks we want to release and which we want to remove from all locks queues;
1162
+ - `:acquirer_id` - (required) `[String]`
1163
+ - acquirer indentifier whose locks we want to release and which we want to remove from all locks queues;
1164
+ - `:lock_scan_size` - (optional) `[Integer]`
1165
+ - how many items will be released at a time (uses `SCAN `for batch extraction and `DEL` for batch deletion);
1166
+ - pre-configuerd value in `config['clear_locks_of__lock_scan_size']`;
1167
+ - `:queue_scan_size` - (optional) `[Integer]`
1168
+ - how many queues will be SCAN'ned at a time (uses `SCAN)`;
1169
+ - pre-configuerd value in `config['clear_locks_of__queue_scan_size']`;
1170
+ - `:logger` - (optional) `[::Logger,#debug]`
1171
+ - custom logger object;
1172
+ - pre-configured value in `config['logger']`;
1173
+ - `:instrumenter` - (optional) `[#notify]`
1174
+ - custom instrumenter object;
1175
+ - pre-configured value in `config['isntrumenter']`;
1176
+ - `:instrument` - (optional) `[NilClass,Any]`
1177
+ - custom instrumentation data wich will be passed to the instrumenter's payload with `:instrument` key;
1178
+ - `:log_sampling_enabled` - (optional) `[Boolean]`
1179
+ - enables **log sampling**;
1180
+ - pre-configured in `config['log_sampling_enabled']`;
1181
+ - `:log_sampling_percent` - (optional) `[Integer]`
1182
+ - **log sampling**:the percent of cases that should be logged;
1183
+ - pre-configured in `config['log_sampling_percent']`;
1184
+ - `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
1185
+ - **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
1186
+ - pre-configured in `config['log_sampler']`;
1187
+ - `log_sample_this` - (optional) `[Boolean]`
1188
+ - marks the method that everything should be logged despite the enabled log sampling;
1189
+ - makes sense when log sampling is enabled;
1190
+ - `false` by default;
1191
+ - `:instr_sampling_enabled` - (optional) `[Boolean]`
1192
+ - enables **instrumentaion sampling**;
1193
+ - pre-configured in `config['instr_sampling_enabled']`;
1194
+ - `instr_sampling_percent` - (optional) `[Integer]`
1195
+ - the percent of cases that should be instrumented;
1196
+ - pre-configured in `config['instr_sampling_percent']`;
1197
+ - `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
1198
+ - percent-based log sampler that decides should be RQL case instrumented or not;
1199
+ - pre-configured in `config['instr_sampler']`;
1200
+ - `instr_sample_this` - (optional) `[Boolean]`
1201
+ - marks the method that everything should be instrumneted despite the enabled instrumentation sampling;
1202
+ - makes sense when instrumentation sampling is enabled;
1203
+ - `false` by default;
1204
+ - returns:
1205
+ - `[Hash<Symbol,Numeric>]` - Format: `{ ok: true, result: Hash<Symbol,Numeric> }`;
1206
+ - result data:
1207
+ - `:rel_time` - `Numeric` - time spent;
1208
+ - `:rel_key_cnt` - `Integer` - the count of released locks;
1209
+ - `:tch_queue_cnt` - `Integer` - the count of touched (modified) queues (the number of queues from which the acquirer/host was removed);
1210
+
1211
+ ```ruby
1212
+ rql.clear_locks_of(
1213
+ host_id: "rql:hst:41478/4320/4360/848818f09d8c3420",
1214
+ acquirer_id: "rql:acq:41478/4320/4340/4360/848818f09d8c3420"
1215
+ )
1216
+ # -- or (alias) --
1217
+ rql.release_locks_of(
1218
+ host_id: "rql:hst:41478/4320/4360/848818f09d8c3420",
1219
+ acquirer_id: "rql:acq:41478/4320/4340/4360/848818f09d8c3420"
1220
+ )
1221
+
1222
+ # -> result
1223
+ {
1224
+ ok: true,
1225
+ result: {
1226
+ rel_key_cnt: 123,
1227
+ tch_queue_cnt: 2,
1228
+ rel_time: 0.1
1229
+ }
1230
+ }
1231
+ ```
1232
+
1233
+ ```ruby
1234
+ # clear locks and queues of the current acquirer:
1235
+ rql.clear_locks_of(
1236
+ host_id: rql.current_host_id,
1237
+ acquirer_id: rql.current_acquirer_id
1238
+ )
1239
+
1240
+ # equivalent:
1241
+ rql.clear_current_locks
1242
+
1243
+ # -> result
1244
+ {
1245
+ ok: true,
1246
+ result: {
1247
+ rel_key_cnt: 43,
1248
+ tch_queue_cnt: 3,
1249
+ rel_time: 0.2
1250
+ }
1251
+ }
1252
+ ```
1253
+
1254
+ ---
1255
+
1256
+ #### #clear_current_locks
1257
+
1258
+ <sup>\[[back to top](#usage)\]</sup>
1259
+
1260
+ - release all locks of the current acquirer/host and remove the current acquirer/host from all queues (locks will be released first);
1261
+ - this is a cleanup helper intended for operational and debugging scenarios (for example: your
1262
+ current puma request thread is killed by Rack::Timeout and you need to cleanup all zombie RQL
1263
+ locks and lock reuqests obtained during the request processing);
1264
+ - representes an equivalent invocation:
1265
+ ```ruby
1266
+ rql.clear_locks_of(host_id: rql.current_host_id, acquirer_id: rql.current_acquirer_id)
1267
+ ```
1268
+ - produces `"redis_queued_locks.release_locks_of"` instrumentation event;
1269
+ - `:lock_scan_size` - (optional) `[Integer]`
1270
+ - how many items will be released at a time (uses `SCAN `for batch extraction and `DEL` for batch deletion);
1271
+ - pre-configuerd value in `config['clear_locks_of__lock_scan_size']`;
1272
+ - `:queue_scan_size` - (optional) `[Integer]`
1273
+ - how many queues will be SCAN'ned at a time (uses `SCAN)`;
1274
+ - pre-configuerd value in `config['clear_locks_of__queue_scan_size']`;
1275
+ - `:logger` - (optional) `[::Logger,#debug]`
1276
+ - custom logger object;
1277
+ - pre-configured value in `config['logger']`;
1278
+ - `:instrumenter` - (optional) `[#notify]`
1279
+ - custom instrumenter object;
1280
+ - pre-configured value in `config['isntrumenter']`;
1281
+ - `:instrument` - (optional) `[NilClass,Any]`
1282
+ - custom instrumentation data wich will be passed to the instrumenter's payload with `:instrument` key;
1283
+ - `:log_sampling_enabled` - (optional) `[Boolean]`
1284
+ - enables **log sampling**;
1285
+ - pre-configured in `config['log_sampling_enabled']`;
1286
+ - `:log_sampling_percent` - (optional) `[Integer]`
1287
+ - **log sampling**:the percent of cases that should be logged;
1288
+ - pre-configured in `config['log_sampling_percent']`;
1289
+ - `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
1290
+ - **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
1291
+ - pre-configured in `config['log_sampler']`;
1292
+ - `log_sample_this` - (optional) `[Boolean]`
1293
+ - marks the method that everything should be logged despite the enabled log sampling;
1294
+ - makes sense when log sampling is enabled;
1295
+ - `false` by default;
1296
+ - `:instr_sampling_enabled` - (optional) `[Boolean]`
1297
+ - enables **instrumentaion sampling**;
1298
+ - pre-configured in `config['instr_sampling_enabled']`;
1299
+ - `instr_sampling_percent` - (optional) `[Integer]`
1300
+ - the percent of cases that should be instrumented;
1301
+ - pre-configured in `config['instr_sampling_percent']`;
1302
+ - `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
1303
+ - percent-based log sampler that decides should be RQL case instrumented or not;
1304
+ - pre-configured in `config['instr_sampler']`;
1305
+ - `instr_sample_this` - (optional) `[Boolean]`
1306
+ - marks the method that everything should be instrumneted despite the enabled instrumentation sampling;
1307
+ - makes sense when instrumentation sampling is enabled;
1308
+ - `false` by default;
1309
+ - returns:
1310
+ - `[Hash<Symbol,Numeric>]` - Format: `{ ok: true, result: Hash<Symbol,Numeric> }`;
1311
+ - result data:
1312
+ - `:rel_time` - `Numeric` - time spent;
1313
+ - `:rel_key_cnt` - `Integer` - the count of released locks;
1314
+ - `:tch_queue_cnt` - `Integer` - the count of touched (modified) queues (the number of queues from which the acquirer/host was removed);
1315
+
1316
+ ```ruby
1317
+ rql.clear_current_locks
1318
+ # -- or (alias) --
1319
+ rql.release_current_locks
1320
+ # equivalent:
1321
+ rql.release_locks_of(host_id: rql.current_host_id, acquirer_id: rql.current_acquirer_id)
1322
+
1323
+ # -> result
1324
+ {
1325
+ ok: true,
1326
+ result: {
1327
+ rel_key_cnt: 43,
1328
+ tch_queue_cnt: 3,
1329
+ rel_time: 0.2
1330
+ }
1331
+ }
1332
+ ```
1333
+
1334
+ ---
1335
+
1121
1336
  #### #extend_lock_ttl
1122
1337
 
1123
1338
  <sup>\[[back to top](#usage)\]</sup>
@@ -1131,35 +1346,35 @@ rql.clear_locks
1131
1346
  - how many milliseconds should be added to the lock's TTL;
1132
1347
  - `:instrumenter` - (optional) `[#notify]`
1133
1348
  - custom instrumenter object;
1134
- - pre-configured in `config[:instrumetner]`;
1349
+ - pre-configured in `config['instrumetner']`;
1135
1350
  - `:instrument` - (optional) `[NilClass,Any]`;
1136
1351
  - custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
1137
1352
  - `nil` by default (no additional data);
1138
1353
  - `:logger` - (optional) `[::Logger,#debug]`
1139
1354
  - custom logger object;
1140
- - pre-configured in `config[:logger]`;
1355
+ - pre-configured in `config['logger']`;
1141
1356
  - `:log_sampling_enabled` - (optional) `[Boolean]`
1142
1357
  - enables **log sampling**;
1143
- - pre-configured in `config[:log_sampling_enabled]`;
1358
+ - pre-configured in `config['log_sampling_enabled']`;
1144
1359
  - `:log_sampling_percent` - (optional) `[Integer]`
1145
1360
  - **log sampling**:the percent of cases that should be logged;
1146
- - pre-configured in `config[:log_sampling_percent]`;
1361
+ - pre-configured in `config['log_sampling_percent']`;
1147
1362
  - `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
1148
1363
  - **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
1149
- - pre-configured in `config[:log_sampler]`;
1364
+ - pre-configured in `config['log_sampler']`;
1150
1365
  - `log_sample_this` - (optional) `[Boolean]`
1151
1366
  - marks the method that everything should be logged despite the enabled log sampling;
1152
1367
  - makes sense when log sampling is enabled;
1153
1368
  - `false` by default;
1154
1369
  - `:instr_sampling_enabled` - (optional) `[Boolean]`
1155
1370
  - enables **instrumentaion sampling**;
1156
- - pre-configured in `config[:instr_sampling_enabled]`;
1371
+ - pre-configured in `config['instr_sampling_enabled']`;
1157
1372
  - `instr_sampling_percent` - (optional) `[Integer]`
1158
1373
  - the percent of cases that should be instrumented;
1159
- - pre-configured in `config[:instr_sampling_percent]`;
1374
+ - pre-configured in `config['instr_sampling_percent']`;
1160
1375
  - `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
1161
1376
  - percent-based log sampler that decides should be RQL case instrumented or not;
1162
- - pre-configured in `config[:instr_sampler]`;
1377
+ - pre-configured in `config['instr_sampler']`;
1163
1378
  - `instr_sample_this` - (optional) `[Boolean]`
1164
1379
  - marks the method that everything should be instrumneted despite the enabled instrumentation sampling;
1165
1380
  - makes sense when instrumentation sampling is enabled;
@@ -1199,7 +1414,7 @@ rql.extend_lock_ttl("my_lock", 5_000) # NOTE: add 5_000 milliseconds
1199
1414
  - get list of obtained locks;
1200
1415
  - uses redis `SCAN` under the hood;
1201
1416
  - accepts:
1202
- - `:scan_size` - `Integer` - (`config[:key_extraction_batch_size]` by default);
1417
+ - `:scan_size` - `Integer` - (`config['key_extraction_batch_size']` by default);
1203
1418
  - `:with_info` - `Boolean` - `false` by default (for details see [#locks_info](#locks_info---get-list-of-locks-with-their-info));
1204
1419
  - returns:
1205
1420
  - `Set<String>` (for `with_info: false`);
@@ -1232,7 +1447,7 @@ rql.locks # or rql.locks(scan_size: 123)
1232
1447
  - get list of lock request queues;
1233
1448
  - uses redis `SCAN` under the hood;
1234
1449
  - accepts
1235
- - `:scan_size` - `Integer` - (`config[:key_extraction_batch_size]` by default);
1450
+ - `:scan_size` - `Integer` - (`config['key_extraction_batch_size']` by default);
1236
1451
  - `:with_info` - `Boolean` - `false` by default (for details see [#queues_info](#queues_info---get-list-of-queues-with-their-info));
1237
1452
  - returns:
1238
1453
  - `Set<String>` (for `with_info: false`);
@@ -1265,7 +1480,7 @@ rql.queues # or rql.queues(scan_size: 123)
1265
1480
  - get list of taken locks and queues;
1266
1481
  - uses redis `SCAN` under the hood;
1267
1482
  - accepts:
1268
- `:scan_size` - `Integer` - (`config[:key_extraction_batch_size]` by default);
1483
+ `:scan_size` - `Integer` - (`config['key_extraction_batch_size']` by default);
1269
1484
  - returns: `Set<String>`
1270
1485
 
1271
1486
  ```ruby
@@ -1298,7 +1513,7 @@ rql.keys # or rql.keys(scan_size: 123)
1298
1513
 
1299
1514
  - get list of locks with their info;
1300
1515
  - uses redis `SCAN` under the hod;
1301
- - accepts `scan_size:`/`Integer` option (`config[:key_extraction_batch_size]` by default);
1516
+ - accepts `scan_size:`/`Integer` option (`config['key_extraction_batch_size']` by default);
1302
1517
  - returns `Set<Hash<Symbol,Any>>` (see [#lock_info](#lock_info) and examples below for details).
1303
1518
  - contained data: `{ lock: String, status: Symbol, info: Hash<String,Any> }`;
1304
1519
  - `:lock` - `String` - lock key in Redis;
@@ -1318,7 +1533,7 @@ rql.locks_info # or rql.locks_info(scan_size: 123)
1318
1533
  :status=>:alive,
1319
1534
  :info=>{
1320
1535
  "acq_id"=>"rql:acq:41478/4320/4340/4360/848818f09d8c3420",
1321
- "hst_id"=>"rql:hst:41478/4320/4360/848818f09d8c3420"
1536
+ "hst_id"=>"rql:hst:41478/4320/4360/848818f09d8c3420",
1322
1537
  "ts"=>1711607112.670343,
1323
1538
  "ini_ttl"=>15000,
1324
1539
  "rem_ttl"=>13998}},
@@ -1336,11 +1551,11 @@ rql.locks_info # or rql.locks_info(scan_size: 123)
1336
1551
 
1337
1552
  - get list of queues with their info;
1338
1553
  - uses redis `SCAN` under the hod;
1339
- - accepts `scan_size:`/`Integer` option (`config[:key_extraction_batch_size]` by default);
1554
+ - accepts `scan_size:`/`Integer` option (`config['key_extraction_batch_size']` by default);
1340
1555
  - returns `Set<Hash<Symbol,Any>>` (see [#queue_info](#queue_info) and examples below for details).
1341
1556
  - contained data: `{ queue: String, requests: Array<Hash<String,Any>> }`
1342
1557
  - `:queue` - `String` - lock key queue in Redis;
1343
- - `:requests` - `Array<Hash<String,Any>>` - lock requests in the que with their acquier id and score.
1558
+ - `:requests` - `Array<Hash<String,Any>>` - lock requests in the que with their acquirer id and score.
1344
1559
 
1345
1560
  ```ruby
1346
1561
  rql.queues_info # or rql.qeuues_info(scan_size: 123)
@@ -1371,7 +1586,7 @@ For this case your lock reuquest will be cleared only when any process will try
1371
1586
  to acquire this lock again (cuz lock acquirement triggers the removement of expired requests).
1372
1587
 
1373
1588
  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[:dead_request_ttl]`.
1589
+ with corresponding `:dead_ttl` option, that is pre-configured by default via `config['dead_request_ttl']`.
1375
1590
 
1376
1591
  `:dead_ttl` option is required because of it is no any **fast** and **resource-free** way to understand which request
1377
1592
  is dead now and is it really dead cuz each request queue can host their requests with
@@ -1380,41 +1595,41 @@ a custom queue ttl for each request differently.
1380
1595
  Accepts:
1381
1596
  - `:dead_ttl` - (optional) `[Integer]`
1382
1597
  - lock request ttl after which a lock request is considered dead;
1383
- - has a preconfigured value in `config[:dead_request_ttl]` (1 day by default);
1598
+ - has a preconfigured value in `config['dead_request_ttl']` (1 day by default);
1384
1599
  - `:sacn_size` - (optional) `[Integer]`
1385
1600
  - the batch of scanned keys for Redis'es SCAN command;
1386
- - has a preconfigured valie in `config[:lock_release_batch_size]`;
1601
+ - has a preconfigured valie in `config['lock_release_batch_size']`;
1387
1602
  - `:logger` - (optional) `[::Logger,#debug]`
1388
1603
  - custom logger object;
1389
- - pre-configured in `config[:logger]`;
1604
+ - pre-configured in `config['logger']`;
1390
1605
  - `:instrumenter` - (optional) `[#notify]`
1391
1606
  - custom instrumenter object;
1392
- - pre-configured in `config[:isntrumenter]`;
1607
+ - pre-configured in `config['isntrumenter']`;
1393
1608
  - `:instrument` - (optional) `[NilClass,Any]`
1394
1609
  - custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
1395
1610
  - `nil` by default (no additional data);
1396
1611
  - `:log_sampling_enabled` - (optional) `[Boolean]`
1397
1612
  - enables **log sampling**;
1398
- - pre-configured in `config[:log_sampling_enabled]`;
1613
+ - pre-configured in `config['log_sampling_enabled']`;
1399
1614
  - `:log_sampling_percent` - (optional) `[Integer]`
1400
1615
  - **log sampling**:the percent of cases that should be logged;
1401
- - pre-configured in `config[:log_sampling_percent]`;
1616
+ - pre-configured in `config['log_sampling_percent']`;
1402
1617
  - `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
1403
1618
  - **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
1404
- - pre-configured in `config[:log_sampler]`;
1619
+ - pre-configured in `config['log_sampler']`;
1405
1620
  - `log_sample_this` - (optional) `[Boolean]`
1406
1621
  - marks the method that everything should be logged despite the enabled log sampling;
1407
1622
  - makes sense when log sampling is enabled;
1408
1623
  - `false` by default;
1409
1624
  - `:instr_sampling_enabled` - (optional) `[Boolean]`
1410
1625
  - enables **instrumentaion sampling**;
1411
- - pre-configured in `config[:instr_sampling_enabled]`;
1626
+ - pre-configured in `config['instr_sampling_enabled']`;
1412
1627
  - `instr_sampling_percent` - (optional) `[Integer]`
1413
1628
  - the percent of cases that should be instrumented;
1414
- - pre-configured in `config[:instr_sampling_percent]`;
1629
+ - pre-configured in `config['instr_sampling_percent']`;
1415
1630
  - `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
1416
1631
  - percent-based log sampler that decides should be RQL case instrumented or not;
1417
- - pre-configured in `config[:instr_sampler]`;
1632
+ - pre-configured in `config['instr_sampler']`;
1418
1633
  - `instr_sample_this` - (optional) `[Boolean]`
1419
1634
  - marks the method that everything should be instrumneted despite the enabled instrumentation sampling;
1420
1635
  - makes sense when instrumentation sampling is enabled;
@@ -1443,6 +1658,7 @@ rql.clear_dead_requests(dead_ttl: 60 * 60 * 1000) # 1 hour in milliseconds
1443
1658
 
1444
1659
  <sup>\[[back to top](#usage)\]</sup>
1445
1660
 
1661
+ - (aliases: `#current_acq_id`, `#acq_id`);
1446
1662
  - get the current acquirer identifier in RQL notation that you can use for debugging purposes during the lock analyzation;
1447
1663
  - acquirer identifier format:
1448
1664
  ```ruby
@@ -1464,7 +1680,7 @@ Accepts:
1464
1680
  - `identity:` - (optional) `[String,Any]`;
1465
1681
  - this value is calculated once during `RedisQueuedLock::Client` instantiation and stored in `@uniq_identity`;
1466
1682
  - this value can be accessed from `RedisQueuedLock::Client#uniq_identity`;
1467
- - [Configuration](#configuration) documentation: see `config[:uniq_identifier]`;
1683
+ - [Configuration](#configuration) documentation: see `config['uniq_identifier']`;
1468
1684
  - [#lock](#lock---obtain-a-lock) method documentation: see `uniq_identifier`;
1469
1685
 
1470
1686
  ```ruby
@@ -1480,6 +1696,7 @@ rql.current_acquirer_id
1480
1696
 
1481
1697
  <sup>\[[back to top](#usage)\]</sup>
1482
1698
 
1699
+ - (aliases: `#current_hst_id`, `#hst_id`);
1483
1700
  - get a current host identifier in RQL notation that you can use for debugging purposes during the lock analyzis;
1484
1701
  - the host is a ruby worker (a combination of process/thread/ractor/identity) that is alive and can obtain locks;
1485
1702
  - the host is limited to `process`/`thread`/`ractor` (without `fiber`) combination cuz we have no abilities to extract
@@ -1505,7 +1722,7 @@ Accepts:
1505
1722
  - `identity:` - (optional) `[String]`;
1506
1723
  - this value is calculated once during `RedisQueuedLock::Client` instantiation and stored in `@uniq_identity`;
1507
1724
  - this value can be accessed from `RedisQueuedLock::Client#uniq_identity`;
1508
- - [Configuration](#configuration) documentation: see `config[:uniq_identifier]`;
1725
+ - [Configuration](#configuration) documentation: see `config['uniq_identifier']`;
1509
1726
  - [#lock](#lock---obtain-a-lock) method documentation: see `uniq_identifier`;
1510
1727
 
1511
1728
  ```ruby
@@ -1537,7 +1754,7 @@ Accepts:
1537
1754
  - `identity` - (optional) `[String]`;
1538
1755
  - this value is calculated once during `RedisQueuedLock::Client` instantiation and stored in `@uniq_identity`;
1539
1756
  - this value can be accessed from `RedisQueuedLock::Client#uniq_identity`;
1540
- - [Configuration](#configuration) documentation: see `config[:uniq_identifier]`;
1757
+ - [Configuration](#configuration) documentation: see `config['uniq_identifier']`;
1541
1758
  - [#lock](#lock---obtain-a-lock) method documentation: see `uniq_identifier`;
1542
1759
 
1543
1760
  ```ruby
@@ -1576,7 +1793,7 @@ rql.possible_host_ids
1576
1793
  - [zombies_info](#zombies_info)
1577
1794
  - [zombie_locks](#zombie_locks)
1578
1795
  - [zombie_hosts](#zombie_hosts)
1579
- - [zombie_acquiers](#zombie_acquiers)
1796
+ - [zombie_acquirers](#zombie_acquirers)
1580
1797
 
1581
1798
  <hr>
1582
1799
 
@@ -1592,31 +1809,31 @@ rql.possible_host_ids
1592
1809
 
1593
1810
  clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
1594
1811
  # NOTE: auto-swarm your RQL client after initalization (run swarm elements and their supervisor)
1595
- config.swarm.auto_swarm = false
1812
+ config['swarm.auto_swarm'] = false
1596
1813
 
1597
1814
  # supervisor configs
1598
- config.swarm.supervisor.liveness_probing_period = 2 # NOTE: in seconds
1815
+ config['swarm.supervisor.liveness_probing_period'] = 2 # NOTE: in seconds
1599
1816
 
1600
1817
  # (probe_hosts) host probing configuration
1601
- config.swarm.probe_hosts.enabled_for_swarm = true # NOTE: run host-probing from or not
1602
- config.swarm.probe_hosts.probe_period = 2 # NOTE: (in seconds) the period of time when the probing process is triggered
1818
+ config['swarm.probe_hosts.enabled_for_swarm'] = true # NOTE: run host-probing from or not
1819
+ config['swarm.probe_hosts.probe_period'] = 2 # NOTE: (in seconds) the period of time when the probing process is triggered
1603
1820
  # (probe_hosts) individual redis config
1604
- config.swarm.probe_hosts.redis_config.sentinel = false # NOTE: individual redis config
1605
- config.swarm.probe_hosts.redis_config.pooled = false # NOTE: individual redis config
1606
- config.swarm.probe_hosts.redis_config.config = {} # NOTE: individual redis config
1607
- config.swarm.probe_hosts.redis_config.pool_config = {} # NOTE: individual redis config
1821
+ config['swarm.probe_hosts.redis_config.sentinel'] = false # NOTE: individual redis config
1822
+ config['swarm.probe_hosts.redis_config.pooled'] = false # NOTE: individual redis config
1823
+ config['swarm.probe_hosts.redis_config.config'] = {} # NOTE: individual redis config
1824
+ config['swarm.probe_hosts.redis_config.pool_config'] = {} # NOTE: individual redis config
1608
1825
 
1609
1826
  # (flush_zombies) zombie flushing configuration
1610
- config.swarm.flush_zombies.enabled_for_swarm = true # NOTE: run zombie flushing or not
1611
- config.swarm.flush_zombies.zombie_flush_period = 10 # NOTE: (in seconds) period of time when the zombie flusher is triggered
1612
- config.swarm.flush_zombies.zombie_ttl = 15_000 # NOTE: (in milliseconds) when the lock/host/acquier is considered a zombie
1613
- config.swarm.flush_zombies.zombie_lock_scan_size = 500 # NOTE: scan sizec during zombie flushing
1614
- config.swarm.flush_zombies.zombie_queue_scan_size = 500 # NOTE: scan sizec during zombie flushing
1827
+ config['swarm.flush_zombies.enabled_for_swarm'] = true # NOTE: run zombie flushing or not
1828
+ config['swarm.flush_zombies.zombie_flush_period'] = 10 # NOTE: (in seconds) period of time when the zombie flusher is triggered
1829
+ config['swarm.flush_zombies.zombie_ttl'] = 15_000 # NOTE: (in milliseconds) when the lock/host/acquirer is considered a zombie
1830
+ config['swarm.flush_zombies.zombie_lock_scan_size'] = 500 # NOTE: scan sizec during zombie flushing
1831
+ config['swarm.flush_zombies.zombie_queue_scan_size'] = 500 # NOTE: scan sizec during zombie flushing
1615
1832
  # (flush_zombies) individual redis config
1616
- config.swarm.flush_zombies.redis_config.sentinel = false # NOTE: individual redis config
1617
- config.swarm.flush_zombies.redis_config.pooled = false # NOTE: individual redis config
1618
- config.swarm.flush_zombies.redis_config.config = {} # NOTE: individual redis config
1619
- config.swarm.flush_zombies.redis_config.pool_config = {} # NOTE: individual redis config
1833
+ config['swarm.flush_zombies.redis_config.sentinel'] = false # NOTE: individual redis config
1834
+ config['swarm.flush_zombies.redis_config.pooled'] = false # NOTE: individual redis config
1835
+ config['swarm.flush_zombies.redis_config.config'] = {} # NOTE: individual redis config
1836
+ config['swarm.flush_zombies.redis_config.pool_config'] = {} # NOTE: individual redis config
1620
1837
  end
1621
1838
  ```
1622
1839
  </details>
@@ -1688,7 +1905,7 @@ rql.possible_host_ids
1688
1905
  :zombie_locks=>#<Set: {"rql:lock:kekpek"}>}
1689
1906
  [5] pry(main)> rql.zombie_locks
1690
1907
  => #<Set: {"rql:lock:kekpek"}>
1691
- [6] pry(main)> rql.zombie_acquiers
1908
+ [6] pry(main)> rql.zombie_acquirers
1692
1909
  => #<Set: {"rql:acq:17580/2260/2380/2280/3f16b93973612580"}>
1693
1910
  [7] pry(main)> rql.zombie_hosts
1694
1911
  => #<Set:
@@ -1730,7 +1947,7 @@ rql.possible_host_ids
1730
1947
  :flush_zombies=>{:enabled=>true, :ractor=>{:running=>true, :state=>"running"}, :main_loop=>{:running=>true, :state=>"sleep"}}}
1731
1948
  [11] pry(main)> rql.zombies_info
1732
1949
  => {:zombie_hosts=>#<Set: {}>, :zombie_acquirers=>#<Set: {}>, :zombie_locks=>#<Set: {}>}
1733
- [12] pry(main)> rql.zombie_acquiers
1950
+ [12] pry(main)> rql.zombie_acquirers
1734
1951
  => #<Set: {}>
1735
1952
  [13] pry(main)> rql.zombie_hosts
1736
1953
  => #<Set: {}>
@@ -1761,7 +1978,7 @@ rql.possible_host_ids
1761
1978
  - `: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
1979
  - `: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
1980
  - for current implementation detalis check:
1764
- - [Configuration](#configuration) documentation: see `config.default_access_strategy` config docs;
1981
+ - [Configuration](#configuration) documentation: see `config['default_access_strategy']` config docs;
1765
1982
  - [#lock](#lock---obtain-a-lock) method documentation: see `access_strategy` attribute docs;
1766
1983
 
1767
1984
  ---
@@ -1779,7 +1996,7 @@ rql.possible_host_ids
1779
1996
  "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
1997
  lock's TTL extension accordingly);
1781
1998
  - for current implementation details check:
1782
- - [Configuration](#configuration) documentation: see `config.default_conflict_strategy` config docs;
1999
+ - [Configuration](#configuration) documentation: see `config['default_conflict_strategy']` config docs;
1783
2000
  - [#lock](#lock---obtain-a-lock) method documentation: see `conflict_strategy` attribute docs and the method result data;
1784
2001
 
1785
2002
  ---
@@ -1796,7 +2013,7 @@ rql.possible_host_ids
1796
2013
  ```ruby
1797
2014
  "[redis_queued_locks.start_lock_obtaining]" # (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
1798
2015
  "[redis_queued_locks.start_try_to_lock_cycle]" # (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
1799
- "[redis_queued_locks.dead_score_reached__reset_acquier_position]" # (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
2016
+ "[redis_queued_locks.dead_score_reached__reset_acquirer_position]" # (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
1800
2017
  "[redis_queued_locks.lock_obtained]" # (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acq_time");
1801
2018
  "[redis_queued_locks.extendable_reentrant_lock_obtained]" # (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat", "acq_time");
1802
2019
  "[redis_queued_locks.reentrant_lock_obtained]" # (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat", "acq_time");
@@ -1831,8 +2048,8 @@ rql.possible_host_ids
1831
2048
  <sup>\[[back to top](#table-of-contents)\]</sup>
1832
2049
 
1833
2050
  **NOTICE**: logging can be sampled via:
1834
- - `config.log_samplign_enabled = true` (**false** by default);
1835
- - `config.log_sampler = RedisQueuedLocks::Logging::Sampler` (used by default);
2051
+ - `config['log_samplign_enabled'] = true` (**false** by default);
2052
+ - `config['log_sampler'] = RedisQueuedLocks::Logging::Sampler` (used by default);
1836
2053
  - see **RedisQueuedLocks::Logging::Sampler** implementation in source code for customization details;
1837
2054
 
1838
2055
  ```ruby
@@ -1843,7 +2060,7 @@ rql.possible_host_ids
1843
2060
  # - at this moment the only debug logs are realised in following cases:
1844
2061
  # - "[redis_queued_locks.start_lock_obtaining]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
1845
2062
  # - "[redis_queued_locks.start_try_to_lock_cycle]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
1846
- # - "[redis_queued_locks.dead_score_reached__reset_acquier_position]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
2063
+ # - "[redis_queued_locks.dead_score_reached__reset_acquirer_position]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
1847
2064
  # - "[redis_queued_locks.lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acq_time", "acs_strat");
1848
2065
  # - "[redis_queued_locks.extendable_reentrant_lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acq_time", "acs_strat");
1849
2066
  # - "[redis_queued_locks.reentrant_lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acq_time", "acs_strat");
@@ -1851,7 +2068,7 @@ rql.possible_host_ids
1851
2068
  # - "[redis_queued_locks.expire_lock]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
1852
2069
  # - "[redis_queued_locks.decrease_lock]" (logs "lock_key", "decreased_ttl", "queue_ttl", "acq_id", "hst_id", "acs_strat");
1853
2070
  # - by default uses VoidLogger that does nothing;
1854
- config.logger = RedisQueuedLocks::Logging::VoidLogger
2071
+ config['logger'] = RedisQueuedLocks::Logging::VoidLogger
1855
2072
 
1856
2073
  # (default: false)
1857
2074
  # - adds additional debug logs;
@@ -1870,28 +2087,28 @@ config.logger = RedisQueuedLocks::Logging::VoidLogger
1870
2087
  # - "[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
2088
  # - "[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
2089
  # - "[redis_queued_locks.try_lock.obtain__free_to_acquire]" (logs "lock_key", "queue_ttl", "acq_id", "hst_id", "acs_strat");
1873
- config.log_lock_try = false
2090
+ config['log_lock_try'] = false
1874
2091
 
1875
2092
  # (default: false)
1876
2093
  # - enables <log sampling>: only the configured percent of RQL cases will be logged;
1877
2094
  # - disabled by default;
1878
- # - works in tandem with <config.log_sampling_percent> and <log.sampler> configs;
1879
- config.log_sampling_enabled = false
2095
+ # - works in tandem with <config['log_sampling_percent']> and <config['log_sampler']> configs;
2096
+ config['log_sampling_enabled'] = false
1880
2097
 
1881
2098
  # (default: 15)
1882
2099
  # - the percent of cases that should be logged;
1883
- # - take an effect when <config.log_sampling_enalbed> is true;
1884
- # - works in tandem with <config.log_sampling_enabled> and <config.log_sampler> configs;
1885
- config.log_sampling_percent = 15
2100
+ # - take an effect when <config['log_sampling_enalbed']> is true;
2101
+ # - works in tandem with <config['log_sampling_enabled']> and <config['log_sampler']> configs;
2102
+ config['log_sampling_percent'] = 15
1886
2103
 
1887
2104
  # (default: RedisQueuedLocks::Logging::Sampler)
1888
2105
  # - percent-based log sampler that decides should be RQL case logged or not;
1889
- # - works in tandem with <config.log_sampling_enabled> and <config.log_sampling_percent> configs;
2106
+ # - works in tandem with <config['log_sampling_enabled']> and <config['log_sampling_percent']> configs;
1890
2107
  # - based on the ultra simple percent-based (weight-based) algorithm that uses SecureRandom.rand
1891
2108
  # method so the algorithm error is ~(0%..13%);
1892
2109
  # - you can provide your own log sampler with bettter algorithm that should realize
1893
2110
  # `sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Logging::Sampler` for example);
1894
- config.log_sampler = RedisQueuedLocks::Logging::Sampler
2111
+ config['log_sampler'] = RedisQueuedLocks::Logging::Sampler
1895
2112
  ```
1896
2113
 
1897
2114
  ---
@@ -1903,19 +2120,18 @@ config.log_sampler = RedisQueuedLocks::Logging::Sampler
1903
2120
  - [Instrumentation Events](#instrumentation-events)
1904
2121
  - [Instrumentation Configuration](#instrumentation-configuration)
1905
2122
 
1906
- An instrumentation layer is incapsulated in `instrumenter` object stored in [config](#configuration) (`RedisQueuedLocks::Client#config[:instrumenter]`).
2123
+ An instrumentation layer is incapsulated in `instrumenter` object stored in [config](#configuration) (`RedisQueuedLocks::Client#config['instrumenter']`).
1907
2124
 
1908
- Instrumentation can be sampled. See [Instrumentation Configuration](#instrumentation-configuration) section for details.
2125
+ Instrumentation can be **sampled**. See [Instrumentation Configuration](#instrumentation-configuration) section for details.
1909
2126
 
1910
2127
  Instrumenter object should provide `notify(event, payload)` method with the following signarue:
1911
2128
 
1912
2129
  - `event` - `string`;
1913
2130
  - `payload` - `hash<Symbol,Any>`;
1914
2131
 
1915
- `redis_queued_locks` provides two instrumenters:
2132
+ **RQL** provides two instrumenters:
1916
2133
 
1917
- - `RedisQueuedLocks::Instrument::ActiveSupport` - **ActiveSupport::Notifications** instrumenter
1918
- that instrument events via **ActiveSupport::Notifications** API;
2134
+ - `RedisQueuedLocks::Instrument::ActiveSupport` - **ActiveSupport::Notifications** instrumenter that instrument events via **ActiveSupport::Notifications** API;
1919
2135
  - `RedisQueuedLocks::Instrument::VoidNotifier` - instrumenter that does nothing;
1920
2136
 
1921
2137
  By default `RedisQueuedLocks::Client` is configured with the void notifier (which means "instrumentation is disabled").
@@ -1927,8 +2143,8 @@ By default `RedisQueuedLocks::Client` is configured with the void notifier (whic
1927
2143
  <sup>\[[back to top](#table-of-contents)\]</sup>
1928
2144
 
1929
2145
  **NOTICE**: instrumentation can be sampled via:
1930
- - `config.instr_sampling_enabled = true` (**false** by default);
1931
- - `config.instr_sampler = RedisQueuedLocks::Instrument::Sampler` (used by default);
2146
+ - `config['instr_sampling_enabled'] = true` (**false** by default);
2147
+ - `config['instr_sampler'] = RedisQueuedLocks::Instrument::Sampler` (used by default);
1932
2148
  - see **RedisQueuedLocks::Instrument::Sampler** implementation in source code for customization details;
1933
2149
 
1934
2150
  ```ruby
@@ -1938,28 +2154,28 @@ By default `RedisQueuedLocks::Client` is configured with the void notifier (whic
1938
2154
  # - event: <string> requried;
1939
2155
  # - payload: <hash> requried;
1940
2156
  # - disabled by default via `VoidNotifier`;
1941
- config.instrumenter = RedisQueuedLocks::Instrument::ActiveSupport
2157
+ config['instrumenter'] = RedisQueuedLocks::Instrument::ActiveSupport
1942
2158
 
1943
2159
  # (default: false)
1944
2160
  # - enables <instrumentaion sampling>: only the configured percent of RQL cases will be instrumented;
1945
2161
  # - disabled by default;
1946
- # - works in tandem with <config.instr_sampling_percent and <log.instr_sampler>;
1947
- config.instr_sampling_enabled = false
2162
+ # - works in tandem with <config['instr_sampling_percent']> and <config['instr_sampler']>;
2163
+ config['instr_sampling_enabled'] = false
1948
2164
 
1949
2165
  # (default: 15)
1950
2166
  # - the percent of cases that should be instrumented;
1951
- # - take an effect when <config.instr_sampling_enalbed> is true;
1952
- # - works in tandem with <config.instr_sampling_enabled> and <config.instr_sampler> configs;
1953
- config.instr_sampling_percent = 15
2167
+ # - take an effect when <config['instr_sampling_enalbed']> is true;
2168
+ # - works in tandem with <config['instr_sampling_enabled']> and <config['instr_sampler']> configs;
2169
+ config['instr_sampling_percent'] = 15
1954
2170
 
1955
2171
  # (default: RedisQueuedLocks::Instrument::Sampler)
1956
2172
  # - percent-based log sampler that decides should be RQL case instrumented or not;
1957
- # - works in tandem with <config.instr_sampling_enabled> and <config.instr_sampling_percent> configs;
2173
+ # - works in tandem with <config['instr_sampling_enabled']> and <config['instr_sampling_percent']> configs;
1958
2174
  # - based on the ultra simple percent-based (weight-based) algorithm that uses SecureRandom.rand
1959
2175
  # method so the algorithm error is ~(0%..13%);
1960
2176
  # - you can provide your own log sampler with bettter algorithm that should realize
1961
2177
  # `sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Instrument::Sampler` for example);
1962
- config.instr_sampler = RedisQueuedLocks::Instrument::Sampler
2178
+ config['instr_sampler'] = RedisQueuedLocks::Instrument::Sampler
1963
2179
  ```
1964
2180
 
1965
2181
  ---
@@ -1970,95 +2186,113 @@ config.instr_sampler = RedisQueuedLocks::Instrument::Sampler
1970
2186
 
1971
2187
  List of instrumentation events
1972
2188
 
1973
- - `redis_queued_locks.lock_obtained`;
1974
- - `redis_queued_locks.extendable_reentrant_lock_obtained`;
1975
- - `redis_queued_locks.reentrant_lock_obtained`;
1976
- - `redis_queued_locks.lock_hold_and_release`;
1977
- - `redis_queued_locks.reentrant_lock_hold_completes`;
1978
- - `redis_queued_locks.explicit_lock_release`;
1979
- - `redis_queued_locks.explicit_all_locks_release`;
2189
+ - ["redis_queued_locks.lock_obtained"](#redis_queued_lockslock_hold_and_release)
2190
+ - ["redis_queued_locks.extendable_reentrant_lock_obtained"](#redis_queued_locksextendable_reentrant_lock_obtained)
2191
+ - ["redis_queued_locks.reentrant_lock_obtained"](#redis_queued_locksreentrant_lock_obtained)
2192
+ - ["redis_queued_locks.lock_hold_and_release"](#redis_queued_lockslock_hold_and_release)
2193
+ - ["redis_queued_locks.reentrant_lock_hold_completes"](#redis_queued_locksreentrant_lock_hold_completes)
2194
+ - ["redis_queued_locks.explicit_lock_release"](#redis_queued_locksexplicit_lock_release)
2195
+ - ["redis_queued_locks.explicit_all_locks_release"](#redis_queued_locksexplicit_all_locks_release)
2196
+ - ["redis_queued_locks.release_locks_of"](#redis_queued_locksrelease_locks_of)
1980
2197
 
1981
2198
  Detalized event semantics and payload structure:
1982
2199
 
1983
- - `"redis_queued_locks.lock_obtained"`
1984
- - a moment when the lock was obtained;
1985
- - raised from `#lock`/`#lock!`;
1986
- - payload:
1987
- - `:ttl` - `integer`/`milliseconds` - lock ttl;
1988
- - `:acq_id` - `string` - lock acquier identifier;
1989
- - `:hst_id` - `string` - lock's host identifier;
1990
- - `:lock_key` - `string` - lock name;
1991
- - `:ts` - `numeric`/`epoch` - the time when the lock was obtaiend;
1992
- - `:acq_time` - `float`/`milliseconds` - time spent on lock acquiring;
1993
- - `:instrument` - `nil`/`Any` - custom data passed to the `#lock`/`#lock!` method as `:instrument` attribute;
1994
-
1995
- - `"redis_queued_locks.extendable_reentrant_lock_obtained"`
1996
- - an event signalizes about the "extendable reentrant lock" obtaining is happened;
1997
- - raised from `#lock`/`#lock!` when the lock was obtained as reentrant lock;
1998
- - payload:
1999
- - `:lock_key` - `string` - lock name;
2000
- - `:ttl` - `integer`/`milliseconds` - last lock ttl by reentrant locking;
2001
- - `:acq_id` - `string` - lock acquier identifier;
2002
- - `:hst_id` - `string` - lock's host identifier;
2003
- - `:ts` - `numeric`/`epoch` - the time when the lock was obtaiend as extendable reentrant lock;
2004
- - `:acq_time` - `float`/`milliseconds` - time spent on lock acquiring;
2005
- - `:instrument` - `nil`/`Any` - custom data passed to the `#lock`/`#lock!` method as `:instrument` attribute;
2006
-
2007
- - `"redis_queued_locks.reentrant_lock_obtained"`
2008
- - an event signalizes about the "reentrant lock" obtaining is happened (without TTL extension);
2009
- - raised from `#lock`/`#lock!` when the lock was obtained as reentrant lock;
2010
- - payload:
2011
- - `:lock_key` - `string` - lock name;
2012
- - `:ttl` - `integer`/`milliseconds` - last lock ttl by reentrant locking;
2013
- - `:acq_id` - `string` - lock acquier identifier;
2014
- - `:hst_id` - `string` - lock's host identifier;
2015
- - `:ts` - `numeric`/`epoch` - the time when the lock was obtaiend as reentrant lock;
2016
- - `:acq_time` - `float`/`milliseconds` - time spent on lock acquiring;
2017
- - `:instrument` - `nil`/`Any` - custom data passed to the `#lock`/`#lock!` method as `:instrument` attribute;
2018
-
2019
- - `"redis_queued_locks.lock_hold_and_release"`
2020
- - an event signalizes about the "hold+and+release" process is finished;
2021
- - raised from `#lock`/`#lock!` when invoked with a block of code;
2022
- - payload:
2023
- - `:hold_time` - `float`/`milliseconds` - lock hold time;
2024
- - `:ttl` - `integer`/`milliseconds` - lock ttl;
2025
- - `:acq_id` - `string` - lock acquier identifier;
2026
- - `:hst_id` - `string` - lock's host identifier;
2027
- - `:lock_key` - `string` - lock name;
2028
- - `:ts` - `numeric`/`epoch` - the time when lock was obtained;
2029
- - `:acq_time` - `float`/`milliseconds` - time spent on lock acquiring;
2030
- - `:instrument` - `nil`/`Any` - custom data passed to the `#lock`/`#lock!` method as `:instrument` attribute;
2031
-
2032
- - `"redis_queued_locks.reentrant_lock_hold_completes"`
2033
- - an event signalizes about the "reentrant lock hold" is complete (both extendable and non-extendable);
2034
- - lock re-entering can happen many times and this event happens for each of them separately;
2035
- - raised from `#lock`/`#lock!` when the lock was obtained as reentrant lock;
2036
- - payload:
2037
- - `:hold_time` - `float`/`milliseconds` - lock hold time;
2038
- - `:ttl` - `integer`/`milliseconds` - last lock ttl by reentrant locking;
2039
- - `:acq_id` - `string` - lock acquier identifier;
2040
- - `:hst_id` - `string` - lock's host identifier;
2041
- - `:ts` - `numeric`/`epoch` - the time when the lock was obtaiend as reentrant lock;
2042
- - `:lock_key` - `string` - lock name;
2043
- - `:acq_time` - `float`/`milliseconds` - time spent on lock acquiring;
2044
- - `:instrument` - `nil`/`Any` - custom data passed to the `#lock`/`#lock!` method as `:instrument` attribute;
2045
-
2046
- - `"redis_queued_locks.explicit_lock_release"`
2047
- - an event signalizes about the explicit lock release (invoked via `RedisQueuedLock#unlock`);
2048
- - raised from `#unlock`;
2049
- - payload:
2050
- - `:at` - `float`/`epoch` - the time when the lock was released;
2051
- - `:rel_time` - `float`/`milliseconds` - time spent on lock releasing;
2052
- - `:lock_key` - `string` - released lock (lock name);
2053
- - `:lock_key_queue` - `string` - released lock queue (lock queue name);
2054
-
2055
- - `"redis_queued_locks.explicit_all_locks_release"`
2056
- - an event signalizes about the explicit all locks release (invoked via `RedisQueuedLock#clear_locks`);
2057
- - raised from `#clear_locks`;
2058
- - payload:
2059
- - `:rel_time` - `float`/`milliseconds` - time spent on "realese all locks" operation;
2060
- - `:at` - `float`/`epoch` - the time when the operation has ended;
2061
- - `:rel_keys` - `integer` - released redis keys count (`released queue keys` + `released lock keys`);
2200
+ ##### `"redis_queued_locks.lock_obtained"`
2201
+ - <sup>\[[back to the list](#instrumentation-events)\]</sup>
2202
+ - a moment when the lock was obtained;
2203
+ - raised from `#lock`/`#lock!`;
2204
+ - payload:
2205
+ - `:ttl` - `integer`/`milliseconds` - lock ttl;
2206
+ - `:acq_id` - `string` - lock acquirer identifier;
2207
+ - `:hst_id` - `string` - lock's host identifier;
2208
+ - `:lock_key` - `string` - lock name;
2209
+ - `:ts` - `numeric`/`epoch` - the time when the lock was obtaiend;
2210
+ - `:acq_time` - `float`/`milliseconds` - time spent on lock acquiring;
2211
+ - `:instrument` - `nil`/`Any` - custom data passed to the `#lock`/`#lock!` method as `:instrument` attribute;
2212
+
2213
+ ##### `"redis_queued_locks.extendable_reentrant_lock_obtained"`
2214
+ - <sup>\[[back to the list](#instrumentation-events)\]</sup>
2215
+ - an event signalizes about the "extendable reentrant lock" obtaining is happened;
2216
+ - raised from `#lock`/`#lock!` when the lock was obtained as reentrant lock;
2217
+ - payload:
2218
+ - `:lock_key` - `string` - lock name;
2219
+ - `:ttl` - `integer`/`milliseconds` - last lock ttl by reentrant locking;
2220
+ - `:acq_id` - `string` - lock acquirer identifier;
2221
+ - `:hst_id` - `string` - lock's host identifier;
2222
+ - `:ts` - `numeric`/`epoch` - the time when the lock was obtaiend as extendable reentrant lock;
2223
+ - `:acq_time` - `float`/`milliseconds` - time spent on lock acquiring;
2224
+ - `:instrument` - `nil`/`Any` - custom data passed to the `#lock`/`#lock!` method as `:instrument` attribute;
2225
+
2226
+ ##### `"redis_queued_locks.reentrant_lock_obtained"`
2227
+ - <sup>\[[back to the list](#instrumentation-events)\]</sup>
2228
+ - an event signalizes about the "reentrant lock" obtaining is happened (without TTL extension);
2229
+ - raised from `#lock`/`#lock!` when the lock was obtained as reentrant lock;
2230
+ - payload:
2231
+ - `:lock_key` - `string` - lock name;
2232
+ - `:ttl` - `integer`/`milliseconds` - last lock ttl by reentrant locking;
2233
+ - `:acq_id` - `string` - lock acquirer identifier;
2234
+ - `:hst_id` - `string` - lock's host identifier;
2235
+ - `:ts` - `numeric`/`epoch` - the time when the lock was obtaiend as reentrant lock;
2236
+ - `:acq_time` - `float`/`milliseconds` - time spent on lock acquiring;
2237
+ - `:instrument` - `nil`/`Any` - custom data passed to the `#lock`/`#lock!` method as `:instrument` attribute;
2238
+
2239
+ ##### `"redis_queued_locks.lock_hold_and_release"`
2240
+ - <sup>\[[back to the list](#instrumentation-events)\]</sup>
2241
+ - an event signalizes about the "hold+and+release" process is finished;
2242
+ - raised from `#lock`/`#lock!` when invoked with a block of code;
2243
+ - payload:
2244
+ - `:hold_time` - `float`/`milliseconds` - lock hold time;
2245
+ - `:ttl` - `integer`/`milliseconds` - lock ttl;
2246
+ - `:acq_id` - `string` - lock acquirer identifier;
2247
+ - `:hst_id` - `string` - lock's host identifier;
2248
+ - `:lock_key` - `string` - lock name;
2249
+ - `:ts` - `numeric`/`epoch` - the time when lock was obtained;
2250
+ - `:acq_time` - `float`/`milliseconds` - time spent on lock acquiring;
2251
+ - `:instrument` - `nil`/`Any` - custom data passed to the `#lock`/`#lock!` method as `:instrument` attribute;
2252
+
2253
+ ##### `"redis_queued_locks.reentrant_lock_hold_completes"`
2254
+ - <sup>\[[back to the list](#instrumentation-events)\]</sup>
2255
+ - an event signalizes about the "reentrant lock hold" is complete (both extendable and non-extendable);
2256
+ - lock re-entering can happen many times and this event happens for each of them separately;
2257
+ - raised from `#lock`/`#lock!` when the lock was obtained as reentrant lock;
2258
+ - payload:
2259
+ - `:hold_time` - `float`/`milliseconds` - lock hold time;
2260
+ - `:ttl` - `integer`/`milliseconds` - last lock ttl by reentrant locking;
2261
+ - `:acq_id` - `string` - lock acquirer identifier;
2262
+ - `:hst_id` - `string` - lock's host identifier;
2263
+ - `:ts` - `numeric`/`epoch` - the time when the lock was obtaiend as reentrant lock;
2264
+ - `:lock_key` - `string` - lock name;
2265
+ - `:acq_time` - `float`/`milliseconds` - time spent on lock acquiring;
2266
+ - `:instrument` - `nil`/`Any` - custom data passed to the `#lock`/`#lock!` method as `:instrument` attribute;
2267
+
2268
+ ##### `"redis_queued_locks.explicit_lock_release"`
2269
+ - <sup>\[[back to the list](#instrumentation-events)\]</sup>
2270
+ - an event signalizes about the explicit lock release (invoked via `RedisQueuedLock#unlock`);
2271
+ - raised from `#unlock`;
2272
+ - payload:
2273
+ - `:at` - `float`/`epoch` - the time when the lock was released;
2274
+ - `:rel_time` - `float`/`milliseconds` - time spent on lock releasing;
2275
+ - `:lock_key` - `string` - released lock (lock name);
2276
+ - `:lock_key_queue` - `string` - released lock queue (lock queue name);
2277
+
2278
+ ##### `"redis_queued_locks.explicit_all_locks_release"`
2279
+ - <sup>\[[back to the list](#instrumentation-events)\]</sup>
2280
+ - an event signalizes about the explicit all locks release (invoked via `RedisQueuedLock#clear_locks`);
2281
+ - raised from `#clear_locks`;
2282
+ - payload:
2283
+ - `:rel_time` - `float`/`milliseconds` - time spent on "realese all locks" operation;
2284
+ - `:at` - `float`/`epoch` - the time when the operation has ended;
2285
+ - `:rel_keys` - `integer` - released redis keys count (`released queue keys` + `released lock keys`);
2286
+
2287
+ ##### `"redis_queued_locks.release_locks_of"`
2288
+ - <sup>\[[back to the list](#instrumentation-events)\]</sup>
2289
+ - an event signalizes about the released locks of the cocnrete host and acquirer;
2290
+ - raised from `#clear_locks_of` and `#clear_current_locks` (`#release_locks_of` and `#release_current_locks` respectively);
2291
+ - payload:
2292
+ - `:rel_time` - `float`/`milliseconds` - time spent on "release locks of" operation;
2293
+ - `:at` - `float`/`epoch` - the time when the opertaion has ended;
2294
+ - `:rel_key_cnt` - `integer` - released locks count;
2295
+ - `:tch_queue_cnt` - `:integer` - the number of queues from which the cocnrete host/acquirer was removed;
2062
2296
 
2063
2297
  ---
2064
2298
 
@@ -2082,8 +2316,26 @@ Detalized event semantics and payload structure:
2082
2316
  ```ruby
2083
2317
  rql.lock_series('lock_a', 'lock_b', 'lock_c') { puts 'locked' }
2084
2318
  ```
2085
- - `light mode`: an ability to work without any debug and instrumentation logic and data (totally reduced debugging and instrumenting possibilities, but better performance);
2319
+ - an ability to release all locks and all requests of the concrete acquirer id or host id (or both in validation-orianted combination);
2320
+ - 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);
2321
+ - a convenient way to mark any `lock` invocation as "non-instrumentable" / "non-loggable" (as an alternative to `VoidNotifier` and to `VoidLogger`);
2322
+ - `Read`/`Write` semantics: you can mark your locks as `read` or `write` lock in order to simulate `read`/`write` lock behavior:
2323
+ - `read` - watis - `write`;
2324
+ - `read` - not waits - `read`;
2325
+ - `write` - waits - `read`;
2326
+ - `write` - waits - `write`;
2327
+ - **write** mode is a default behavior for all RQL locks;
2086
2328
  - **Minor**:
2329
+ - add `hst_id` to all methods that works with queues info;
2330
+ - try to return the `fiber object id` to the lock host identifier (we cant use fiber object id cuz `ObjectSpace` has no access to the fiber object space after the any ractor object initialization)
2331
+ - named RQL's threads (`Thread#name`) and RQL's ractors (`Ractor#name`) in order to have an ability to find and work with RQL's threads and ractors outside of RQL logic (stop threads before process forking, for example);
2332
+ - `#lock`/`#lock!` - `timeout:` option: support for granular periods (it supports only `seconds` at the moment, but we need `milliseconds`);
2333
+ - 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;
2334
+ - Add `ignore timeout errors` ability (for debug purposes);
2335
+ - 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);
2336
+ - Renaming of some exceptions (such as `RedisQueuedLocks::TimedLockTimeoutError`) to make the related problem more quickly, faster and easier to understand;
2337
+ - Support for detailed `OpenTelemetry` tracing;
2338
+ - `light mode`: an ability to work without any debug and instrumentation logic and data (totally reduced debugging and instrumenting possibilities, but better performance);
2087
2339
  - support for `Dragonfly` database backend (https://github.com/dragonflydb/dragonfly) (https://www.dragonflydb.io/);
2088
2340
  - (_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);
2089
2341
  - Semantic error objects for unexpected Redis errors;
@@ -2092,15 +2344,41 @@ Detalized event semantics and payload structure:
2092
2344
  whose ttl may expire before the block execution completes). It makes sense for non-`timed` locks *only*;
2093
2345
  - sized lock queues (with an ability of dynamically growing size);
2094
2346
  - better code stylization (+ some refactorings);
2095
- - `RedisQueuedLocks::Acquier::Try.try_to_lock` - detailed successful result analization;
2347
+ - `RedisQueuedLocks::Acquirer::Try.try_to_lock` - detailed successful result analization;
2096
2348
  - Support for LIFO strategy;
2097
2349
  - better specs with 100% test coverage (total specs rework);
2098
2350
  - statistics with UI;
2099
2351
  - JSON log formatter;
2100
- - RBS type signatures;
2101
2352
  - **automatic** deadlock detection;
2102
2353
  - `go`-lang implementation;
2103
2354
  - (_research_) simplification and speedup of the internal "redis-communuication-and-data-storing"-based algorithms;
2355
+ - `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);
2356
+ - **Research**: support for `Valkey` database backend (https://github.com/valkey-io/valkey) (https://valkey.io/);
2357
+ - **Research**: support for `Garnet` database backend (https://microsoft.github.io/) (https://github.com/microsoft/garnet);
2358
+ - add a library-level exception, when RQL-related key in Redis (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);
2359
+ ---
2360
+
2361
+ ## Build and Develop
2362
+
2363
+ - Tests (`RSpec`):
2364
+ ```shell
2365
+ bundle exec rake rspec
2366
+ ```
2367
+
2368
+ - Linting (`Rubocop`+`RBS`):
2369
+ ```shell
2370
+ bundle exec rake rubocop
2371
+ ```
2372
+
2373
+ - `Static` TypeChecking (`Steep`):
2374
+ ```shell
2375
+ bundle exec rake steep:check
2376
+ ```
2377
+
2378
+ - `Runtime` TypeChecking (`RBS`):
2379
+ ```shell
2380
+ bundle exec rbs collection install && RBS_TEST_RAISE=true RUBYOPT='-rrbs/test/setup' RBS_TEST_OPT='-I sig' RBS_TEST_LOGLEVEL=error RBS_TEST_TARGET='RedisQueuedLocks::*' bundle exec rspec --failure-exit-code=0
2381
+ ```
2104
2382
 
2105
2383
  ---
2106
2384