redis_queued_locks 1.5.0 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -1
- data/README.md +234 -58
- data/lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +36 -0
- data/lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue.rb +39 -0
- data/lib/redis_queued_locks/acquier/acquire_lock/instr_visitor.rb +151 -0
- data/lib/redis_queued_locks/acquier/acquire_lock/log_visitor.rb +192 -0
- data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock/log_visitor.rb +485 -0
- data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock.rb +76 -197
- data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire/log_visitor.rb +68 -0
- data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire.rb +17 -21
- data/lib/redis_queued_locks/acquier/acquire_lock.rb +128 -123
- data/lib/redis_queued_locks/acquier/clear_dead_requests.rb +8 -1
- data/lib/redis_queued_locks/acquier/extend_lock_ttl.rb +12 -2
- data/lib/redis_queued_locks/acquier/release_all_locks.rb +44 -8
- data/lib/redis_queued_locks/acquier/release_lock.rb +46 -14
- data/lib/redis_queued_locks/client.rb +128 -31
- data/lib/redis_queued_locks/instrument/sampler.rb +27 -0
- data/lib/redis_queued_locks/instrument.rb +47 -0
- data/lib/redis_queued_locks/logging/sampler.rb +10 -3
- data/lib/redis_queued_locks/logging.rb +1 -0
- data/lib/redis_queued_locks/utilities.rb +0 -1
- data/lib/redis_queued_locks/version.rb +2 -2
- data/lib/redis_queued_locks/watcher.rb +1 -0
- data/redis_queued_locks.gemspec +23 -3
- metadata +15 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd303479ce60c268e630d4ad770657cbe0223cffcb9990d31a9bb3de92d80843
|
4
|
+
data.tar.gz: 2a19bfed90da70fa8c49bf069a2acd110d3840eeb78f1f21767416c28e5bc6b7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c2d6c956bfc7227cd45c33c8b983ae759e13bf7149121c272821922d66a4be73b57b344e2042f86d0391acbe92de794013e0a67ce6157b402c6a0ca0a3a1740
|
7
|
+
data.tar.gz: e00ec46afd8e5d8ebef469c0a5d86a026562f8060e8abc95c4f3e89aa9351dc8961fe2d9d181aa4e8203056c74fb4aa8c4043f925b93a5b477c44541eec5ad9f
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,22 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [1.7.0] - 2024-06-12
|
4
|
+
### Added
|
5
|
+
- New feature: **Lock Access Strategy**: you can obtain a lock in different ways: `queued` (classic queued FIFO), `random` (get the lock immideatly if lock is free), and soon: `lifo` and `barrier`;
|
6
|
+
- `:queued` is used by default (classic `redis_queued_locks` behavior);
|
7
|
+
- `:random`: obtain a lock without checking the positions in the queue => if lock is free to obtain - it will be obtained;
|
8
|
+
### Changed
|
9
|
+
- Some logging refactorings, some instrumentation refactorings: the code that uses them is more readable and supportable;
|
10
|
+
|
11
|
+
## [1.6.0] - 2024-05-25
|
12
|
+
### Added
|
13
|
+
- New Feature: **Instrumentation Sampling**: configurable instrumentation sampling based on `weight` algorithm (where the weight is a percentage of RQL cases that should be logged);
|
14
|
+
- Missing instrumenter customization in public `RedisQueuedLocks::Client` methods;
|
15
|
+
- Documentation updates;
|
16
|
+
|
3
17
|
## [1.5.0] - 2024-05-23
|
4
18
|
### Added
|
5
|
-
- New Feature: **Log sampling** - configurable log sampling based on `weight` algorithm (where the weight is a percentage);
|
19
|
+
- New Feature: **Log sampling** - configurable log sampling based on `weight` algorithm (where the weight is a percentage of RQL cases that should be logged);
|
6
20
|
|
7
21
|
## [1.4.0] - 2024-05-13
|
8
22
|
### Added
|
data/README.md
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
|
5
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.
|
6
6
|
|
7
|
+
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
|
+
|
7
9
|
Provides flexible invocation flow, parametrized limits (lock request ttl, lock ttl, queue ttl, lock attempts limit, fast failing, etc), logging and instrumentation.
|
8
10
|
|
9
11
|
---
|
@@ -32,6 +34,9 @@ Provides flexible invocation flow, parametrized limits (lock request ttl, lock t
|
|
32
34
|
- [locks_info](#locks_info---get-list-of-locks-with-their-info)
|
33
35
|
- [queues_info](#queues_info---get-list-of-queues-with-their-info)
|
34
36
|
- [clear_dead_requests](#clear_dead_requests)
|
37
|
+
- [Lock Access Strategies](#lock-access-strategies)
|
38
|
+
- [queued](#lock-access-strategies)
|
39
|
+
- [random](#lock-access-strategies)
|
35
40
|
- [Dead locks and Reentrant locks](#dead-locks-and-reentrant-locks)
|
36
41
|
- [Logging](#logging)
|
37
42
|
- [Instrumentation](#instrumentation)
|
@@ -69,6 +74,8 @@ Provides flexible invocation flow, parametrized limits (lock request ttl, lock t
|
|
69
74
|
|
70
75
|
> 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) which guarantees that the request queue will never be stacked.
|
71
76
|
|
77
|
+
> 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.
|
78
|
+
|
72
79
|
**Soon**: detailed explanation.
|
73
80
|
|
74
81
|
---
|
@@ -150,9 +157,20 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
|
|
150
157
|
# - should be all blocks of code are timed by default;
|
151
158
|
config.is_timed_by_default = false
|
152
159
|
|
160
|
+
# (symbol) (default: :queued)
|
161
|
+
# - Defines the way in which the lock should be obitained;
|
162
|
+
# - By default it is configured to obtain a lock in classic `queued` way:
|
163
|
+
# you should wait your position in queue in order to obtain a lock;
|
164
|
+
# - Can be customized in methods `#lock` and `#lock!` via `:access_strategy` attribute (see method signatures of #lock and #lock! methods);
|
165
|
+
# - Supports different strategies:
|
166
|
+
# - `:queued` (FIFO): the classic queued behavior (default), your lock will be obitaned if you are first in queue and the required lock is free;
|
167
|
+
# - `:random` (RANDOM): obtain a lock without checking the positions in the queue (but with checking the limist,
|
168
|
+
# retries, timeouts and so on). if lock is free to obtain - it will be obtained;
|
169
|
+
config.default_access_strategy = :queued
|
170
|
+
|
153
171
|
# (symbol) (default: :wait_for_lock)
|
154
172
|
# - Global default conflict strategy mode;
|
155
|
-
# - Can be customized in methods `#lock` and `#lock
|
173
|
+
# - Can be customized in methods `#lock` and `#lock!` via `:conflict_strategy` attribute (see method signatures of #lock and #lock! methods);
|
156
174
|
# - Conflict strategy is a logical behavior for cases when the process that obtained the lock want to acquire this lock again;
|
157
175
|
# - Realizes "reentrant locks" abstraction (same process conflict / same process deadlock);
|
158
176
|
# - By default uses `:wait_for_lock` strategy (classic way);
|
@@ -202,15 +220,15 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
|
|
202
220
|
# - should implement `debug(progname = nil, &block)` (minimal requirement) or be an instance of Ruby's `::Logger` class/subclass;
|
203
221
|
# - supports `SemanticLogger::Logger` (see "semantic_logger" gem)
|
204
222
|
# - at this moment the only debug logs are realised in following cases:
|
205
|
-
# - "[redis_queued_locks.start_lock_obtaining]" (logs "lock_key", "queue_ttl", "acq_id");
|
206
|
-
# - "[redis_queued_locks.start_try_to_lock_cycle]" (logs "lock_key", "queue_ttl", "acq_id");
|
207
|
-
# - "[redis_queued_locks.dead_score_reached__reset_acquier_position]" (logs "lock_key", "queue_ttl", "acq_id");
|
208
|
-
# - "[redis_queued_locks.lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "acq_time");
|
209
|
-
# - "[redis_queued_locks.extendable_reentrant_lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "acq_time");
|
210
|
-
# - "[redis_queued_locks.reentrant_lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "acq_time");
|
211
|
-
# - "[redis_queued_locks.fail_fast_or_limits_reached_or_deadlock__dequeue]" (logs "lock_key", "queue_ttl", "acq_id");
|
212
|
-
# - "[redis_queued_locks.expire_lock]" (logs "lock_key", "queue_ttl", "acq_id");
|
213
|
-
# - "[redis_queued_locks.decrease_lock]" (logs "lock_key", "decreased_ttl", "queue_ttl", "acq_id");
|
223
|
+
# - "[redis_queued_locks.start_lock_obtaining]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
224
|
+
# - "[redis_queued_locks.start_try_to_lock_cycle]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
225
|
+
# - "[redis_queued_locks.dead_score_reached__reset_acquier_position]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
226
|
+
# - "[redis_queued_locks.lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "acq_time", "acs_strat");
|
227
|
+
# - "[redis_queued_locks.extendable_reentrant_lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "acq_time", "acs_strat");
|
228
|
+
# - "[redis_queued_locks.reentrant_lock_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "acq_time", "acs_strat");
|
229
|
+
# - "[redis_queued_locks.fail_fast_or_limits_reached_or_deadlock__dequeue]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
230
|
+
# - "[redis_queued_locks.expire_lock]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
231
|
+
# - "[redis_queued_locks.decrease_lock]" (logs "lock_key", "decreased_ttl", "queue_ttl", "acq_id", "acs_strat");
|
214
232
|
# - by default uses VoidLogger that does nothing;
|
215
233
|
config.logger = RedisQueuedLocks::Logging::VoidLogger
|
216
234
|
|
@@ -218,19 +236,19 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
|
|
218
236
|
# - adds additional debug logs;
|
219
237
|
# - enables additional logs for each internal try-retry lock acquiring (a lot of logs can be generated depending on your retry configurations);
|
220
238
|
# - it adds following logs in addition to the existing:
|
221
|
-
# - "[redis_queued_locks.try_lock.start]" (logs "lock_key", "queue_ttl", "acq_id");
|
222
|
-
# - "[redis_queued_locks.try_lock.rconn_fetched]" (logs "lock_key", "queue_ttl", "acq_id");
|
223
|
-
# - "[redis_queued_locks.try_lock.same_process_conflict_detected]" (logs "lock_key", "queue_ttl", "acq_id");
|
224
|
-
# - "[redis_queued_locks.try_lock.same_process_conflict_analyzed]" (logs "lock_key", "queue_ttl", "acq_id", "spc_status");
|
225
|
-
# - "[redis_queued_locks.try_lock.reentrant_lock__extend_and_work_through]" (logs "lock_key", "queue_ttl", "acq_id", "spc_status", "last_ext_ttl", "last_ext_ts");
|
226
|
-
# - "[redis_queued_locks.try_lock.reentrant_lock__work_through]" (logs "lock_key", "queue_ttl", "acq_id", "spc_status", last_spc_ts);
|
227
|
-
# - "[redis_queued_locks.try_lock.acq_added_to_queue]" (logs "lock_key", "queue_ttl", "acq_id)";
|
228
|
-
# - "[redis_queued_locks.try_lock.remove_expired_acqs]" (logs "lock_key", "queue_ttl", "acq_id");
|
229
|
-
# - "[redis_queued_locks.try_lock.get_first_from_queue]" (logs "lock_key", "queue_ttl", "acq_id", "first_acq_id_in_queue");
|
230
|
-
# - "[redis_queued_locks.try_lock.exit__queue_ttl_reached]" (logs "lock_key", "queue_ttl", "acq_id");
|
231
|
-
# - "[redis_queued_locks.try_lock.exit__no_first]" (logs "lock_key", "queue_ttl", "acq_id", "first_acq_id_in_queue", "<current_lock_data>");
|
232
|
-
# - "[redis_queued_locks.try_lock.exit__lock_still_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "first_acq_id_in_queue", "locked_by_acq_id", "<current_lock_data>");
|
233
|
-
# - "[redis_queued_locks.try_lock.obtain__free_to_acquire]" (logs "lock_key", "queue_ttl", "acq_id");
|
239
|
+
# - "[redis_queued_locks.try_lock.start]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
240
|
+
# - "[redis_queued_locks.try_lock.rconn_fetched]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
241
|
+
# - "[redis_queued_locks.try_lock.same_process_conflict_detected]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
242
|
+
# - "[redis_queued_locks.try_lock.same_process_conflict_analyzed]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat", "spc_status");
|
243
|
+
# - "[redis_queued_locks.try_lock.reentrant_lock__extend_and_work_through]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat", "spc_status", "last_ext_ttl", "last_ext_ts");
|
244
|
+
# - "[redis_queued_locks.try_lock.reentrant_lock__work_through]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat", "spc_status", last_spc_ts);
|
245
|
+
# - "[redis_queued_locks.try_lock.acq_added_to_queue]" (logs "lock_key", "queue_ttl", "acq_id, "acs_strat")";
|
246
|
+
# - "[redis_queued_locks.try_lock.remove_expired_acqs]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
247
|
+
# - "[redis_queued_locks.try_lock.get_first_from_queue]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat", "first_acq_id_in_queue");
|
248
|
+
# - "[redis_queued_locks.try_lock.exit__queue_ttl_reached]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
249
|
+
# - "[redis_queued_locks.try_lock.exit__no_first]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat", "first_acq_id_in_queue", "<current_lock_data>");
|
250
|
+
# - "[redis_queued_locks.try_lock.exit__lock_still_obtained]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat", "first_acq_id_in_queue", "locked_by_acq_id", "<current_lock_data>");
|
251
|
+
# - "[redis_queued_locks.try_lock.obtain__free_to_acquire]" (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
234
252
|
config.log_lock_try = false
|
235
253
|
|
236
254
|
# (default: false)
|
@@ -253,6 +271,27 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
|
|
253
271
|
# - you can provide your own log sampler with bettter algorithm that should realize
|
254
272
|
# `sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Logging::Sampler` for example);
|
255
273
|
config.log_sampler = RedisQueuedLocks::Logging::Sampler
|
274
|
+
|
275
|
+
# (default: false)
|
276
|
+
# - enables <instrumentaion sampling>: only the configured percent of RQL cases will be instrumented;
|
277
|
+
# - disabled by default;
|
278
|
+
# - works in tandem with <config.instr_sampling_percent and <log.instr_sampler>;
|
279
|
+
config.instr_sampling_enabled = false
|
280
|
+
|
281
|
+
# (default: 15)
|
282
|
+
# - the percent of cases that should be instrumented;
|
283
|
+
# - take an effect when <config.instr_sampling_enalbed> is true;
|
284
|
+
# - works in tandem with <config.instr_sampling_enabled> and <config.instr_sampler> configs;
|
285
|
+
config.instr_sampling_percent = 15
|
286
|
+
|
287
|
+
# (default: RedisQueuedLocks::Instrument::Sampler)
|
288
|
+
# - percent-based log sampler that decides should be RQL case instrumented or not;
|
289
|
+
# - works in tandem with <config.instr_sampling_enabled> and <config.instr_sampling_percent> configs;
|
290
|
+
# - based on the ultra simple percent-based (weight-based) algorithm that uses SecureRandom.rand
|
291
|
+
# method so the algorithm error is ~(0%..13%);
|
292
|
+
# - you can provide your own log sampler with bettter algorithm that should realize
|
293
|
+
# `sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Instrument::Sampler` for example);
|
294
|
+
config.instr_sampler = RedisQueuedLocks::Instrument::Sampler
|
256
295
|
end
|
257
296
|
```
|
258
297
|
|
@@ -306,14 +345,19 @@ def lock(
|
|
306
345
|
raise_errors: false,
|
307
346
|
fail_fast: false,
|
308
347
|
conflict_strategy: config[:default_conflict_strategy],
|
348
|
+
access_strategy: config[:default_access_strategy],
|
309
349
|
identity: uniq_identity, # (attr_accessor) calculated during client instantiation via config[:uniq_identifier] proc;
|
310
350
|
meta: nil,
|
311
351
|
instrument: nil,
|
352
|
+
instrumenter: config[:instrumenter],
|
312
353
|
logger: config[:logger],
|
313
354
|
log_lock_try: config[:log_lock_try],
|
314
355
|
log_sampling_enabled: config[:log_sampling_enabled],
|
315
356
|
log_sampling_percent: config[:log_sampling_percent],
|
316
357
|
log_sampler: config[:log_sampler],
|
358
|
+
instr_sampling_enabled: config[:instr_sampling_enabled],
|
359
|
+
instr_sampling_percent: config[:instr_sampling_percent],
|
360
|
+
instr_sampler: config[:instr_sampler],
|
317
361
|
&block
|
318
362
|
)
|
319
363
|
```
|
@@ -346,16 +390,28 @@ def lock(
|
|
346
390
|
- See RedisQueuedLocks::Instrument::ActiveSupport for example;
|
347
391
|
- See [Instrumentation](#instrumentation) section of docs;
|
348
392
|
- pre-configured in `config[:isntrumenter]` with void notifier (`RedisQueuedLocks::Instrumenter::VoidNotifier`);
|
393
|
+
- `instrument` - (optional) `[NilClass,Any]`
|
394
|
+
- Custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
|
395
|
+
- `nil` by default (means "no custom instrumentation data");
|
349
396
|
- `raise_errors` - (optional) `[Boolean]`
|
350
397
|
- Raise errors on library-related limits (such as timeout or retry count limit) and on lock conflicts (such as same-process dead locks);
|
351
398
|
- `false` by default;
|
352
399
|
- `fail_fast` - (optional) `[Boolean]`
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
- `
|
400
|
+
- Should the required lock to be checked before the try and exit immidietly if lock is
|
401
|
+
already obtained;
|
402
|
+
- Should the logic exit immidietly after the first try if the lock was obtained
|
403
|
+
by another process while the lock request queue was initially empty;
|
404
|
+
- `false` by default;
|
405
|
+
- `access_strategy` - (optional) - `[Symbol]`
|
406
|
+
- Defines the way in which the lock should be obitained (in queued way, in random way and so on);
|
407
|
+
- By default it is configured to obtain a lock in classic `:queued` way: you should wait your position in queue in order to obtain a lock;
|
408
|
+
- Supports following strategies:
|
409
|
+
- `:queued` (FIFO): (default) the classic queued behavior, your lock will be obitaned if you are first in queue and the required lock is free;
|
410
|
+
- `:random` (RANDOM): obtain a lock without checking the positions in the queue (but with checking the limist, retries, timeouts and so on).
|
411
|
+
if lock is free to obtain - it will be obtained;
|
412
|
+
- pre-configured in `config[:default_access_strategy]`;
|
413
|
+
- See [Lock Access Strategies](#lock-access-strategies) documentation section for details;
|
414
|
+
- `conflict_strategy` - (optional) - `[Symbol]`
|
359
415
|
- The conflict strategy mode for cases when the process that obtained the lock
|
360
416
|
want to acquire this lock again;
|
361
417
|
- By default uses `:wait_for_lock` strategy;
|
@@ -365,7 +421,7 @@ def lock(
|
|
365
421
|
- `:extendable_work_through` - continue working under the lock **with** lock's TTL extension;
|
366
422
|
- `:wait_for_lock` - (default) - work in classic way (with timeouts, retry delays, retry limits, etc - in classic way :));
|
367
423
|
- `:dead_locking` - fail with deadlock exception;
|
368
|
-
- See [Dead locks and Reentrant locks](#dead-locks-and-reentrant-locks)
|
424
|
+
- See [Dead locks and Reentrant locks](#dead-locks-and-reentrant-locks) documentation section for details;
|
369
425
|
- `identity` - (optional) `[String]`
|
370
426
|
- An unique string that is unique per `RedisQueuedLock::Client` instance. Resolves the
|
371
427
|
collisions between the same process_id/thread_id/fiber_id/ractor_id identifiers on different
|
@@ -377,9 +433,6 @@ def lock(
|
|
377
433
|
- A custom metadata wich will be passed to the lock data in addition to the existing data;
|
378
434
|
- Custom metadata can not contain reserved lock data keys (such as `lock_key`, `acq_id`, `ts`, `ini_ttl`, `rem_ttl`);
|
379
435
|
- `nil` by default (means "no metadata");
|
380
|
-
- `instrument` - (optional) `[NilClass,Any]`
|
381
|
-
- Custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
|
382
|
-
- `nil` by default (means "no custom instrumentation data");
|
383
436
|
- `logger` - (optional) `[::Logger,#debug]`
|
384
437
|
- Logger object used for loggin internal mutation oeprations and opertioan results / process progress;
|
385
438
|
- pre-configured in `config[:logger]` with void logger `RedisQueuedLocks::Logging::VoidLogger`;
|
@@ -405,6 +458,24 @@ def lock(
|
|
405
458
|
- you can provide your own log sampler with bettter algorithm that should realize
|
406
459
|
`sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Logging::Sampler` for example);
|
407
460
|
- pre-configured in `config[:log_sampler]`;
|
461
|
+
- `instr_sampling_enabled` - (optional) `[Boolean]`
|
462
|
+
- enables **instrumentaion sampling**: only the configured percent of RQL cases will be instrumented;
|
463
|
+
- disabled by default;
|
464
|
+
- works in tandem with `instr_sampling_percent` and `instr_sampler` options;
|
465
|
+
- pre-configured in `config[:instr_sampling_enabled]`;
|
466
|
+
- `instr_sampling_percent` - (optional) `[Integer]`
|
467
|
+
- the percent of cases that should be instrumented;
|
468
|
+
- take an effect when `instr_sampling_enalbed` is true;
|
469
|
+
- works in tandem with `instr_sampling_enabled` and `instr_sampler` options;
|
470
|
+
- pre-configured in `config[:instr_sampling_percent]`;
|
471
|
+
- `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
|
472
|
+
- percent-based log sampler that decides should be RQL case instrumented or not;
|
473
|
+
- works in tandem with `instr_sampling_enabled` and `instr_sampling_percent` options;
|
474
|
+
- based on the ultra simple percent-based (weight-based) algorithm that uses SecureRandom.rand
|
475
|
+
method so the algorithm error is ~(0%..13%);
|
476
|
+
- you can provide your own log sampler with bettter algorithm that should realize
|
477
|
+
`sampling_happened?(percent) => boolean` interface (see `RedisQueuedLocks::Instrument::Sampler` for example);
|
478
|
+
- pre-configured in `config[:instr_sampler]`;
|
408
479
|
- `block` - (optional) `[Block]`
|
409
480
|
- A block of code that should be executed after the successfully acquired lock.
|
410
481
|
- If block is **passed** the obtained lock will be released after the block execution or it's ttl (what will happen first);
|
@@ -558,7 +629,7 @@ rql.lock("my_lock", queue_ttl: 5, timeout: 10_000, retry_count: nil)
|
|
558
629
|
|
559
630
|
# lock queue: =>
|
560
631
|
[
|
561
|
-
"rql:acq:123/456/567/676/374dd74324",
|
632
|
+
"rql:acq:123/456/567/676/374dd74324",
|
562
633
|
"rql:acq:123/456/567/677/374dd74322", # <- long living lock
|
563
634
|
"rql:acq:123/456/567/679/374dd74321",
|
564
635
|
"rql:acq:123/456/567/683/374dd74322", # <== we are here
|
@@ -581,7 +652,51 @@ rql.lock("my_lock", queue_ttl: 5, timeout: 10_000, retry_count: nil)
|
|
581
652
|
"rql:acq:123/456/567/685/374dd74329", # some other waiting process
|
582
653
|
"rql:acq:123/456/567/683/374dd74322", # <== we are here (moved to the end of the queue)
|
583
654
|
]
|
655
|
+
```
|
656
|
+
|
657
|
+
- obtain a lock in `:random` way (with `:random` strategy): in `:random` strategy
|
658
|
+
any acquirer from the lcok queue can obtain the lock regardless of the position in the lock queue;
|
584
659
|
|
660
|
+
```ruby
|
661
|
+
# Current Process (process#1)
|
662
|
+
rql.lock('my_lock', ttl: 2_000, access_strategy: :random)
|
663
|
+
# => holds the lock
|
664
|
+
|
665
|
+
# Another Process (process#2)
|
666
|
+
rql.lock('my_lock', retry_delay: 7000, ttl: 4000, access_strategy: :random)
|
667
|
+
# => the lock is not free, stay in a queue and retry...
|
668
|
+
|
669
|
+
# Another Process (process#3)
|
670
|
+
rql.lock('my_lock', retry_delay: 3000, ttl: 3000, access_strategy: :random)
|
671
|
+
# => the lock is not free, stay in a queue and retry...
|
672
|
+
|
673
|
+
# lock queue:
|
674
|
+
[
|
675
|
+
"rql:acq:123/456/567/677/374dd74322", # process#1 (holds the lock)
|
676
|
+
"rql:acq:123/456/567/679/374dd74321", # process#2 (waiting for the lock, in retry)
|
677
|
+
"rql:acq:123/456/567/683/374dd74322", # process#3 (waiting for the lock, in retry)
|
678
|
+
]
|
679
|
+
|
680
|
+
# ... some period of time
|
681
|
+
# -> process#1 => released the lock;
|
682
|
+
# -> process#2 => delayed retry, waiting;
|
683
|
+
# -> process#3 => preparing for retry (the delay is over);
|
684
|
+
# lock queue:
|
685
|
+
[
|
686
|
+
"rql:acq:123/456/567/679/374dd74321", # process#2 (waiting for the lock, DELAYED)
|
687
|
+
"rql:acq:123/456/567/683/374dd74322", # process#3 (trying to obtain the lock, RETRYING now)
|
688
|
+
]
|
689
|
+
|
690
|
+
# ... some period of time
|
691
|
+
# -> process#2 => didn't have time to obtain the lock, delayed retry;
|
692
|
+
# -> process#3 => holds the lock;
|
693
|
+
# lock queue:
|
694
|
+
[
|
695
|
+
"rql:acq:123/456/567/679/374dd74321", # process#2 (waiting for the lock, DELAYED)
|
696
|
+
"rql:acq:123/456/567/683/374dd74322", # process#3 (holds the lock)
|
697
|
+
]
|
698
|
+
|
699
|
+
# `process#3` is the last in queue, but has acquired the lock because his lock request "randomly" came first;
|
585
700
|
```
|
586
701
|
|
587
702
|
---
|
@@ -613,10 +728,15 @@ def lock!(
|
|
613
728
|
logger: config[:logger],
|
614
729
|
log_lock_try: config[:log_lock_try],
|
615
730
|
instrument: nil,
|
731
|
+
instrumenter: config[:instrumenter],
|
732
|
+
access_strategy: config[:default_access_strategy],
|
616
733
|
conflict_strategy: config[:default_conflict_strategy],
|
617
734
|
log_sampling_enabled: config[:log_sampling_enabled],
|
618
735
|
log_sampling_percent: config[:log_sampling_percent],
|
619
736
|
log_sampler: config[:log_sampler],
|
737
|
+
instr_sampling_enabled: config[:instr_sampling_enabled],
|
738
|
+
instr_sampling_percent: config[:instr_sampling_percent],
|
739
|
+
instr_sampler: config[:instr_sampler],
|
620
740
|
&block
|
621
741
|
)
|
622
742
|
```
|
@@ -797,6 +917,15 @@ rql.queued?("your_lock_name") # => true/false
|
|
797
917
|
- `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
|
798
918
|
- **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
|
799
919
|
- pre-configured in `config[:log_sampler]`;
|
920
|
+
- `:instr_sampling_enabled` - (optional) `[Boolean]`
|
921
|
+
- enables **instrumentaion sampling**;
|
922
|
+
- pre-configured in `config[:instr_sampling_enabled]`;
|
923
|
+
- `instr_sampling_percent` - (optional) `[Integer]`
|
924
|
+
- the percent of cases that should be instrumented;
|
925
|
+
- pre-configured in `config[:instr_sampling_percent]`;
|
926
|
+
- `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
|
927
|
+
- percent-based log sampler that decides should be RQL case instrumented or not;
|
928
|
+
- pre-configured in `config[:instr_sampler]`;
|
800
929
|
- if you try to unlock non-existent lock you will receive `ok: true` result with operation timings
|
801
930
|
and `:nothing_to_release` result factor inside;
|
802
931
|
|
@@ -856,6 +985,15 @@ rql.unlock("your_lock_name")
|
|
856
985
|
- `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
|
857
986
|
- **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
|
858
987
|
- pre-configured in `config[:log_sampler]`;
|
988
|
+
- `:instr_sampling_enabled` - (optional) `[Boolean]`
|
989
|
+
- enables **instrumentaion sampling**;
|
990
|
+
- pre-configured in `config[:instr_sampling_enabled]`;
|
991
|
+
- `instr_sampling_percent` - (optional) `[Integer]`
|
992
|
+
- the percent of cases that should be instrumented;
|
993
|
+
- pre-configured in `config[:instr_sampling_percent]`;
|
994
|
+
- `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
|
995
|
+
- percent-based log sampler that decides should be RQL case instrumented or not;
|
996
|
+
- pre-configured in `config[:instr_sampler]`;
|
859
997
|
- returns:
|
860
998
|
- `[Hash<Symbol,Numeric>]` - Format: `{ ok: true, result: Hash<Symbol,Numeric> }`;
|
861
999
|
- result data:
|
@@ -888,6 +1026,12 @@ rql.clear_locks
|
|
888
1026
|
- the lock name which ttl should be extended;
|
889
1027
|
- `milliseconds` - (required) `[Integer]`
|
890
1028
|
- how many milliseconds should be added to the lock's TTL;
|
1029
|
+
- `:instrumenter` - (optional) `[#notify]`
|
1030
|
+
- custom instrumenter object;
|
1031
|
+
- pre-configured in `config[:instrumetner]`;
|
1032
|
+
- `:instrument` - (optional) `[NilClass,Any]`;
|
1033
|
+
- custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
|
1034
|
+
- `nil` by default (no additional data);
|
891
1035
|
- `:logger` - (optional) `[::Logger,#debug]`
|
892
1036
|
- custom logger object;
|
893
1037
|
- pre-configured in `config[:logger]`;
|
@@ -900,6 +1044,15 @@ rql.clear_locks
|
|
900
1044
|
- `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
|
901
1045
|
- **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
|
902
1046
|
- pre-configured in `config[:log_sampler]`;
|
1047
|
+
- `:instr_sampling_enabled` - (optional) `[Boolean]`
|
1048
|
+
- enables **instrumentaion sampling**;
|
1049
|
+
- pre-configured in `config[:instr_sampling_enabled]`;
|
1050
|
+
- `instr_sampling_percent` - (optional) `[Integer]`
|
1051
|
+
- the percent of cases that should be instrumented;
|
1052
|
+
- pre-configured in `config[:instr_sampling_percent]`;
|
1053
|
+
- `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
|
1054
|
+
- percent-based log sampler that decides should be RQL case instrumented or not;
|
1055
|
+
- pre-configured in `config[:instr_sampler]`;
|
903
1056
|
- returns `{ ok: true, result: :ttl_extended }` when ttl is extended;
|
904
1057
|
- returns `{ ok: false, result: :async_expire_or_no_lock }` when a lock not found or a lock is already expired during
|
905
1058
|
some steps of invocation (see **Important** section below);
|
@@ -1137,6 +1290,15 @@ Accepts:
|
|
1137
1290
|
- `:log_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]`
|
1138
1291
|
- **log sampling**: percent-based log sampler that decides should be RQL case logged or not;
|
1139
1292
|
- pre-configured in `config[:log_sampler]`;
|
1293
|
+
- `:instr_sampling_enabled` - (optional) `[Boolean]`
|
1294
|
+
- enables **instrumentaion sampling**;
|
1295
|
+
- pre-configured in `config[:instr_sampling_enabled]`;
|
1296
|
+
- `instr_sampling_percent` - (optional) `[Integer]`
|
1297
|
+
- the percent of cases that should be instrumented;
|
1298
|
+
- pre-configured in `config[:instr_sampling_percent]`;
|
1299
|
+
- `instr_sampler` - (optional) `[#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]`
|
1300
|
+
- percent-based log sampler that decides should be RQL case instrumented or not;
|
1301
|
+
- pre-configured in `config[:instr_sampler]`;
|
1140
1302
|
|
1141
1303
|
Returns: `{ ok: true, processed_queues: Set<String> }` returns the list of processed lock queues;
|
1142
1304
|
|
@@ -1157,6 +1319,22 @@ rql.clear_dead_requests(dead_ttl: 60 * 60 * 1000) # 1 hour in milliseconds
|
|
1157
1319
|
|
1158
1320
|
---
|
1159
1321
|
|
1322
|
+
## Lock Access Strategies
|
1323
|
+
|
1324
|
+
- **this documentation section is in progress**;
|
1325
|
+
- (little details for a context of the current implementation and feautres):
|
1326
|
+
- defines the way in which the lock should be obitained;
|
1327
|
+
- by default it is configured to obtain a lock in classic `queued` way: you should wait your position in queue in order to obtain a lock;
|
1328
|
+
- can be customized in methods `#lock` and `#lock!` via `:access_strategy` attribute (see method signatures of #lock and #lock! methods);
|
1329
|
+
- supports different strategies:
|
1330
|
+
- `:queued` (FIFO): the classic queued behavior (default), your lock will be obitaned if you are first in queue and the required lock is free;
|
1331
|
+
- `: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;
|
1332
|
+
- for current implementation detalis check:
|
1333
|
+
- [Configuration](#configuration) documentation: see `config.default_access_strategy` config docs;
|
1334
|
+
- [#lock](#lock---obtain-a-lock) method documentation: see `access_strategy` attribute docs;
|
1335
|
+
|
1336
|
+
---
|
1337
|
+
|
1160
1338
|
## Dead locks and Reentrant locks
|
1161
1339
|
|
1162
1340
|
<sup>\[[back to top](#table-of-contents)\]</sup>
|
@@ -1182,34 +1360,34 @@ rql.clear_dead_requests(dead_ttl: 60 * 60 * 1000) # 1 hour in milliseconds
|
|
1182
1360
|
- default logs (raised from `#lock`/`#lock!`):
|
1183
1361
|
|
1184
1362
|
```ruby
|
1185
|
-
"[redis_queued_locks.start_lock_obtaining]" # (logs "lock_key", "queue_ttl", "acq_id");
|
1186
|
-
"[redis_queued_locks.start_try_to_lock_cycle]" # (logs "lock_key", "queue_ttl", "acq_id");
|
1187
|
-
"[redis_queued_locks.dead_score_reached__reset_acquier_position]" # (logs "lock_key", "queue_ttl", "acq_id");
|
1363
|
+
"[redis_queued_locks.start_lock_obtaining]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
1364
|
+
"[redis_queued_locks.start_try_to_lock_cycle]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
1365
|
+
"[redis_queued_locks.dead_score_reached__reset_acquier_position]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
1188
1366
|
"[redis_queued_locks.lock_obtained]" # (logs "lock_key", "queue_ttl", "acq_id", "acq_time");
|
1189
|
-
"[redis_queued_locks.extendable_reentrant_lock_obtained]" # (logs "lock_key", "queue_ttl", "acq_id", "acq_time");
|
1190
|
-
"[redis_queued_locks.reentrant_lock_obtained]" # (logs "lock_key", "queue_ttl", "acq_id", "acq_time");
|
1191
|
-
"[redis_queued_locks.fail_fast_or_limits_reached_or_deadlock__dequeue]" # (logs "lock_key", "queue_ttl", "acq_id");
|
1192
|
-
"[redis_queued_locks.expire_lock]" # (logs "lock_key", "queue_ttl", "acq_id");
|
1193
|
-
"[redis_queued_locks.decrease_lock]" # (logs "lock_key", "decreased_ttl", "queue_ttl", "acq_id");
|
1367
|
+
"[redis_queued_locks.extendable_reentrant_lock_obtained]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat", "acq_time");
|
1368
|
+
"[redis_queued_locks.reentrant_lock_obtained]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat", "acq_time");
|
1369
|
+
"[redis_queued_locks.fail_fast_or_limits_reached_or_deadlock__dequeue]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
1370
|
+
"[redis_queued_locks.expire_lock]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
1371
|
+
"[redis_queued_locks.decrease_lock]" # (logs "lock_key", "decreased_ttl", "queue_ttl", "acq_id", "acs_strat");
|
1194
1372
|
```
|
1195
1373
|
|
1196
1374
|
- additional logs (raised from `#lock`/`#lock!` with `confg[:log_lock_try] == true`):
|
1197
1375
|
|
1198
1376
|
```ruby
|
1199
|
-
"[redis_queued_locks.try_lock.start]" # (logs "lock_key", "queue_ttl", "acq_id");
|
1200
|
-
"[redis_queued_locks.try_lock.rconn_fetched]" # (logs "lock_key", "queue_ttl", "acq_id");
|
1201
|
-
"[redis_queued_locks.try_lock.same_process_conflict_detected]" # (logs "lock_key", "queue_ttl", "acq_id");
|
1202
|
-
"[redis_queued_locks.try_lock.same_process_conflict_analyzed]" # (logs "lock_key", "queue_ttl", "acq_id", "spc_status");
|
1203
|
-
"[redis_queued_locks.try_lock.reentrant_lock__extend_and_work_through]" # (logs "lock_key", "queue_ttl", "acq_id", "spc_status", "last_ext_ttl", "last_ext_ts");
|
1204
|
-
"[redis_queued_locks.try_lock.reentrant_lock__work_through]" # (logs "lock_key", "queue_ttl", "acq_id", "spc_status", last_spc_ts);
|
1205
|
-
"[redis_queued_locks.try_lock.single_process_lock_conflict__dead_lock]" # (logs "lock_key", "queue_ttl", "acq_id", "spc_status", "last_spc_ts");
|
1206
|
-
"[redis_queued_locks.try_lock.acq_added_to_queue]" # (logs "lock_key", "queue_ttl", "acq_id)
|
1207
|
-
"[redis_queued_locks.try_lock.remove_expired_acqs]" # (logs "lock_key", "queue_ttl", "acq_id");
|
1208
|
-
"[redis_queued_locks.try_lock.get_first_from_queue]" # (logs "lock_key", "queue_ttl", "acq_id", "first_acq_id_in_queue");
|
1209
|
-
"[redis_queued_locks.try_lock.exit__queue_ttl_reached]" # (logs "lock_key", "queue_ttl", "acq_id");
|
1210
|
-
"[redis_queued_locks.try_lock.exit__no_first]" # (logs "lock_key", "queue_ttl", "acq_id", "first_acq_id_in_queue", "<current_lock_data>");
|
1211
|
-
"[redis_queued_locks.try_lock.exit__lock_still_obtained]" # (logs "lock_key", "queue_ttl", "acq_id", "first_acq_id_in_queue", "locked_by_acq_id", "<current_lock_data>");
|
1212
|
-
"[redis_queued_locks.try_lock.obtain__free_to_acquire]" # (logs "lock_key", "queue_ttl", "acq_id");
|
1377
|
+
"[redis_queued_locks.try_lock.start]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
1378
|
+
"[redis_queued_locks.try_lock.rconn_fetched]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
1379
|
+
"[redis_queued_locks.try_lock.same_process_conflict_detected]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
1380
|
+
"[redis_queued_locks.try_lock.same_process_conflict_analyzed]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat", "spc_status");
|
1381
|
+
"[redis_queued_locks.try_lock.reentrant_lock__extend_and_work_through]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat", "spc_status", "last_ext_ttl", "last_ext_ts");
|
1382
|
+
"[redis_queued_locks.try_lock.reentrant_lock__work_through]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat", "spc_status", last_spc_ts);
|
1383
|
+
"[redis_queued_locks.try_lock.single_process_lock_conflict__dead_lock]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat", "spc_status", "last_spc_ts");
|
1384
|
+
"[redis_queued_locks.try_lock.acq_added_to_queue]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
1385
|
+
"[redis_queued_locks.try_lock.remove_expired_acqs]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
1386
|
+
"[redis_queued_locks.try_lock.get_first_from_queue]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat", "first_acq_id_in_queue");
|
1387
|
+
"[redis_queued_locks.try_lock.exit__queue_ttl_reached]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
1388
|
+
"[redis_queued_locks.try_lock.exit__no_first]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat", "first_acq_id_in_queue", "<current_lock_data>");
|
1389
|
+
"[redis_queued_locks.try_lock.exit__lock_still_obtained]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat", "first_acq_id_in_queue", "locked_by_acq_id", "<current_lock_data>");
|
1390
|
+
"[redis_queued_locks.try_lock.obtain__free_to_acquire]" # (logs "lock_key", "queue_ttl", "acq_id", "acs_strat");
|
1213
1391
|
```
|
1214
1392
|
|
1215
1393
|
---
|
@@ -1335,8 +1513,6 @@ Detalized event semantics and payload structure:
|
|
1335
1513
|
<sup>\[[back to top](#table-of-contents)\]</sup>
|
1336
1514
|
|
1337
1515
|
- **Major**:
|
1338
|
-
- precent-based instrumentation sampling (instrument the concrete % of cases via "sampling" strategy);
|
1339
|
-
- support for Random Access strategy (non-queued behavior);
|
1340
1516
|
- lock request prioritization;
|
1341
1517
|
- **strict redlock algorithm support** (support for many `RedisClient` instances);
|
1342
1518
|
- `#lock_series` - acquire a series of locks:
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 1.7.0
|
5
|
+
module RedisQueuedLocks::Acquier::AcquireLock::DequeueFromLockQueue::LogVisitor
|
6
|
+
extend self
|
7
|
+
|
8
|
+
# @param logger [::Logger,#debug]
|
9
|
+
# @param log_sampled [Boolean]
|
10
|
+
# @param lock_key [String]
|
11
|
+
# @param queue_ttl [Integer]
|
12
|
+
# @param acquier_id [String]
|
13
|
+
# @param access_strategy [Symbol]
|
14
|
+
# @return [void]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
# @since 1.7.0
|
18
|
+
def dequeue_from_lock_queue(
|
19
|
+
logger,
|
20
|
+
log_sampled,
|
21
|
+
lock_key,
|
22
|
+
queue_ttl,
|
23
|
+
acquier_id,
|
24
|
+
access_strategy
|
25
|
+
)
|
26
|
+
return unless log_sampled
|
27
|
+
|
28
|
+
logger.debug do
|
29
|
+
"[redis_queued_locks.fail_fast_or_limits_reached_or_deadlock__dequeue] " \
|
30
|
+
"lock_key => '#{lock_key}' " \
|
31
|
+
"queue_ttl => #{queue_ttl} " \
|
32
|
+
"acq_id => '#{acquier_id}' " \
|
33
|
+
"acs_strat => '#{access_strategy}"
|
34
|
+
end rescue nil
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 1.7.0
|
5
|
+
module RedisQueuedLocks::Acquier::AcquireLock::DequeueFromLockQueue
|
6
|
+
require_relative 'dequeue_from_lock_queue/log_visitor'
|
7
|
+
|
8
|
+
# @param redis [RedisClient]
|
9
|
+
# @param logger [::Logger,#debug]
|
10
|
+
# @param lock_key [String]
|
11
|
+
# @param lock_key_queue [String]
|
12
|
+
# @param queue_ttl [Integer]
|
13
|
+
# @param acquier_id [String]
|
14
|
+
# @param access_strategy [Symbol]
|
15
|
+
# @param log_sampled [Boolean]
|
16
|
+
# @param instr_sampled [Boolean]
|
17
|
+
# @return [Hash<Symbol,Any>] Format: { ok: true/false, result: Any }
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
# @since 1.7.0
|
21
|
+
def dequeue_from_lock_queue(
|
22
|
+
redis,
|
23
|
+
logger,
|
24
|
+
lock_key,
|
25
|
+
lock_key_queue,
|
26
|
+
queue_ttl,
|
27
|
+
acquier_id,
|
28
|
+
access_strategy,
|
29
|
+
log_sampled,
|
30
|
+
instr_sampled
|
31
|
+
)
|
32
|
+
result = redis.call('ZREM', lock_key_queue, acquier_id)
|
33
|
+
LogVisitor.dequeue_from_lock_queue(
|
34
|
+
logger, log_sampled,
|
35
|
+
lock_key, queue_ttl, acquier_id, access_strategy
|
36
|
+
)
|
37
|
+
RedisQueuedLocks::Data[ok: true, result: result]
|
38
|
+
end
|
39
|
+
end
|