redis_queued_locks 1.20.0 → 1.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.claude/project-overview.md +249 -36
- data/.claude/rules/acquirer.md +16 -14
- data/.claude/rules/arguments.md +2 -2
- data/.claude/rules/changelog.md +27 -0
- data/.claude/rules/git.md +1 -1
- data/.claude/rules/logic.md +34 -13
- data/.claude/rules/swarm.md +4 -5
- data/.claude/rules/tests.md +9 -6
- data/.claude/rules/type-checking.md +13 -14
- data/.claude/rules/visitors.md +13 -14
- data/.claude/skills/rql-code-review/SKILL.md +134 -43
- data/CHANGELOG.md +105 -125
- data/CLAUDE.md +11 -9
- data/README.md +501 -136
- data/Rakefile +11 -0
- data/lib/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +1 -0
- data/lib/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rb +68 -10
- data/lib/redis_queued_locks/acquirer/acquire_lock/log_visitor.rb +82 -15
- data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rb +92 -14
- data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rb +441 -63
- data/lib/redis_queued_locks/acquirer/acquire_lock/with_acq_timeout.rb +2 -2
- data/lib/redis_queued_locks/acquirer/acquire_lock/yield_expire/log_visitor.rb +1 -0
- data/lib/redis_queued_locks/acquirer/acquire_lock/yield_expire.rb +5 -5
- data/lib/redis_queued_locks/acquirer/acquire_lock.rb +176 -39
- data/lib/redis_queued_locks/acquirer/clear_dead_requests.rb +322 -49
- data/lib/redis_queued_locks/acquirer/extend_lock_ttl.rb +125 -13
- data/lib/redis_queued_locks/acquirer/is_locked.rb +0 -1
- data/lib/redis_queued_locks/acquirer/is_queued.rb +0 -1
- data/lib/redis_queued_locks/acquirer/keys.rb +16 -3
- data/lib/redis_queued_locks/acquirer/lock_info.rb +31 -39
- data/lib/redis_queued_locks/acquirer/lock_series_poc/instr_visitor.rb +11 -5
- data/lib/redis_queued_locks/acquirer/lock_series_poc/log_visitor.rb +20 -10
- data/lib/redis_queued_locks/acquirer/lock_series_poc.rb +105 -36
- data/lib/redis_queued_locks/acquirer/locks.rb +32 -11
- data/lib/redis_queued_locks/acquirer/queue_info.rb +30 -8
- data/lib/redis_queued_locks/acquirer/queues.rb +26 -6
- data/lib/redis_queued_locks/acquirer/reindex_locks.rb +117 -4
- data/lib/redis_queued_locks/acquirer/release_all_locks.rb +37 -6
- data/lib/redis_queued_locks/acquirer/release_lock.rb +33 -7
- data/lib/redis_queued_locks/acquirer/release_locks_of.rb +45 -6
- data/lib/redis_queued_locks/acquirer/release_read_lock.rb +22 -3
- data/lib/redis_queued_locks/client.rb +140 -56
- data/lib/redis_queued_locks/config.rb +105 -14
- data/lib/redis_queued_locks/errors.rb +34 -4
- data/lib/redis_queued_locks/instrument/sampler.rb +4 -7
- data/lib/redis_queued_locks/logging/sampler.rb +4 -8
- data/lib/redis_queued_locks/resource.rb +137 -12
- data/lib/redis_queued_locks/swarm/flush_zombies.rb +1 -0
- data/lib/redis_queued_locks/swarm/redis_client_builder.rb +8 -4
- data/lib/redis_queued_locks/swarm/swarm_element/threaded.rb +8 -6
- data/lib/redis_queued_locks/swarm/zombie_info.rb +6 -2
- data/lib/redis_queued_locks/swarm.rb +86 -5
- data/lib/redis_queued_locks/utilities.rb +1 -1
- data/lib/redis_queued_locks/version.rb +2 -2
- data/rbs_collection.lock.yaml +4 -0
- data/rbs_collection.yaml +2 -1
- data/sig/manifest.yml +1 -0
- data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rbs +2 -2
- data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue.rbs +2 -2
- data/sig/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rbs +25 -5
- data/sig/redis_queued_locks/acquirer/acquire_lock/log_visitor.rbs +32 -12
- data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rbs +61 -40
- data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rbs +59 -11
- data/sig/redis_queued_locks/acquirer/acquire_lock/{yield_with_expire → yield_expire}/log_visitor.rbs +4 -4
- data/sig/redis_queued_locks/acquirer/acquire_lock/yield_expire.rbs +4 -4
- data/sig/redis_queued_locks/acquirer/acquire_lock.rbs +6 -4
- data/sig/redis_queued_locks/acquirer/clear_dead_requests.rbs +23 -1
- data/sig/redis_queued_locks/acquirer/extend_lock_ttl.rbs +16 -3
- data/sig/redis_queued_locks/acquirer/queues.rbs +1 -1
- data/sig/redis_queued_locks/acquirer/reindex_locks.rbs +22 -1
- data/sig/redis_queued_locks/acquirer/release_lock.rbs +3 -2
- data/sig/redis_queued_locks/acquirer/release_read_lock.rbs +1 -1
- data/sig/redis_queued_locks/client.rbs +24 -10
- data/sig/redis_queued_locks/config.rbs +54 -1
- data/sig/redis_queued_locks/errors.rbs +5 -2
- data/sig/redis_queued_locks/instrument/sampler.rbs +3 -3
- data/sig/redis_queued_locks/instrument/void_notifier.rbs +3 -1
- data/sig/redis_queued_locks/logging/sampler.rbs +3 -3
- data/sig/redis_queued_locks/resource.rbs +23 -13
- data/sig/redis_queued_locks/swarm/swarm_element/threaded.rbs +1 -1
- data/sig/redis_queued_locks/utilities.rbs +2 -1
- data/sig/redis_queued_locks.rbs +7 -0
- data/sig/vendor/redis_client.rbs +1 -0
- metadata +4 -3
- /data/sig/redis_queued_locks/{acquier.rbs → acquirer.rbs} +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# @api public
|
|
4
4
|
# @since 1.0.0
|
|
5
|
-
# @version 1.
|
|
5
|
+
# @version 1.22.0
|
|
6
6
|
# rubocop:disable Metrics/ClassLength
|
|
7
7
|
class RedisQueuedLocks::Client
|
|
8
8
|
# @return [RedisClient]
|
|
@@ -43,7 +43,7 @@ class RedisQueuedLocks::Client
|
|
|
43
43
|
# @version 1.13.0
|
|
44
44
|
def initialize(redis_client, &configuration)
|
|
45
45
|
@config = RedisQueuedLocks::Config.new(&configuration)
|
|
46
|
-
@uniq_identity = config['uniq_identifier'].call
|
|
46
|
+
@uniq_identity = config['uniq_identifier'].call
|
|
47
47
|
@redis_client = redis_client
|
|
48
48
|
@swarm = RedisQueuedLocks::Swarm.new(self)
|
|
49
49
|
@swarm.swarm! if config['swarm.auto_swarm']
|
|
@@ -79,6 +79,7 @@ class RedisQueuedLocks::Client
|
|
|
79
79
|
#
|
|
80
80
|
# @api public
|
|
81
81
|
# @since 1.9.0
|
|
82
|
+
# @version 1.21.0
|
|
82
83
|
def swarm_info(zombie_ttl: config['swarm.flush_zombies.zombie_ttl'])
|
|
83
84
|
swarm.swarm_info(zombie_ttl:)
|
|
84
85
|
end
|
|
@@ -107,6 +108,7 @@ class RedisQueuedLocks::Client
|
|
|
107
108
|
#
|
|
108
109
|
# @api public
|
|
109
110
|
# @since 1.9.0
|
|
111
|
+
# @version 1.21.0
|
|
110
112
|
def flush_zombies(
|
|
111
113
|
zombie_ttl: config['swarm.flush_zombies.zombie_ttl'],
|
|
112
114
|
lock_scan_size: config['swarm.flush_zombies.zombie_lock_scan_size'],
|
|
@@ -121,6 +123,7 @@ class RedisQueuedLocks::Client
|
|
|
121
123
|
#
|
|
122
124
|
# @api public
|
|
123
125
|
# @since 1.9.0
|
|
126
|
+
# @version 1.21.0
|
|
124
127
|
def zombie_locks(
|
|
125
128
|
zombie_ttl: config['swarm.flush_zombies.zombie_ttl'],
|
|
126
129
|
lock_scan_size: config['swarm.flush_zombies.zombie_lock_scan_size']
|
|
@@ -132,8 +135,9 @@ class RedisQueuedLocks::Client
|
|
|
132
135
|
# @option lock_scan_size [Integer]
|
|
133
136
|
# @return [Set<String>]
|
|
134
137
|
#
|
|
135
|
-
# @api
|
|
138
|
+
# @api public
|
|
136
139
|
# @since 1.9.0
|
|
140
|
+
# @version 1.21.0
|
|
137
141
|
def zombie_acquirers(
|
|
138
142
|
zombie_ttl: config['swarm.flush_zombies.zombie_ttl'],
|
|
139
143
|
lock_scan_size: config['swarm.flush_zombies.zombie_lock_scan_size']
|
|
@@ -146,6 +150,7 @@ class RedisQueuedLocks::Client
|
|
|
146
150
|
#
|
|
147
151
|
# @api public
|
|
148
152
|
# @since 1.9.0
|
|
153
|
+
# @version 1.21.0
|
|
149
154
|
def zombie_hosts(zombie_ttl: config['swarm.flush_zombies.zombie_ttl'])
|
|
150
155
|
swarm.zombie_hosts(zombie_ttl:)
|
|
151
156
|
end
|
|
@@ -159,7 +164,7 @@ class RedisQueuedLocks::Client
|
|
|
159
164
|
#
|
|
160
165
|
# @api public
|
|
161
166
|
# @since 1.9.0
|
|
162
|
-
# @version 1.
|
|
167
|
+
# @version 1.21.0
|
|
163
168
|
def zombies_info(
|
|
164
169
|
zombie_ttl: config['swarm.flush_zombies.zombie_ttl'],
|
|
165
170
|
lock_scan_size: config['swarm.flush_zombies.zombie_lock_scan_size']
|
|
@@ -171,7 +176,9 @@ class RedisQueuedLocks::Client
|
|
|
171
176
|
# @param lock_name [String]
|
|
172
177
|
# Lock name to be obtained.
|
|
173
178
|
# @option ttl [Integer]
|
|
174
|
-
# Lock's time to live (in milliseconds)
|
|
179
|
+
# - Lock's time to live (in milliseconds);
|
|
180
|
+
# - a positive Integer;
|
|
181
|
+
# - pre-configured in `config['default_lock_ttl']`;
|
|
175
182
|
# @option queue_ttl [Integer]
|
|
176
183
|
# Lifetime of the acuier's lock request. In seconds.
|
|
177
184
|
# @option lock_index_grace_period [Integer]
|
|
@@ -183,7 +190,8 @@ class RedisQueuedLocks::Client
|
|
|
183
190
|
# mode: the lock index is maintained by all lock acquirements of the client);
|
|
184
191
|
# - pre-configured in `config['lock_index_grace_period']`;
|
|
185
192
|
# @option timeout [Integer,NilClass]
|
|
186
|
-
# Time period whe should try to acquire the lock (in seconds). Nil means "without timeout"
|
|
193
|
+
# Time period whe should try to acquire the lock (in seconds). Nil means "without timeout"
|
|
194
|
+
# (`0` is the same as `nil`).
|
|
187
195
|
# @option timed [Boolean]
|
|
188
196
|
# Limit the invocation time period of the passed block of code by the lock's TTL.
|
|
189
197
|
# @option retry_count [Integer,NilClass]
|
|
@@ -224,8 +232,9 @@ class RedisQueuedLocks::Client
|
|
|
224
232
|
# - `:queued` access strategy orders read and write lock requests in FIFO between modes
|
|
225
233
|
# (read lock request waits for earlier write lock requests, write lock request waits for
|
|
226
234
|
# earlier read and write lock requests) so writers are not starved by readers;
|
|
227
|
-
# - `:random` access strategy
|
|
228
|
-
# writers)
|
|
235
|
+
# - `:random` access strategy: the lock request does not wait for earlier requests (no order
|
|
236
|
+
# between modes: a continuous flow of readers can starve writers), but it is queued like any
|
|
237
|
+
# lock request (`:queued` lock requests wait for it);
|
|
229
238
|
# - read lock specifics:
|
|
230
239
|
# - read lock is released (with a block of code) or expired (by `ttl`) independently
|
|
231
240
|
# of other read locks; `#unlock` releases all read locks and the write lock;
|
|
@@ -247,6 +256,24 @@ class RedisQueuedLocks::Client
|
|
|
247
256
|
# (but with checking the limist, retries, timeouts and so on). if lock is
|
|
248
257
|
# free to obtain - it will be obtained;
|
|
249
258
|
# - pre-configured in `config['default_access_strategy']`;
|
|
259
|
+
# @option priority [Integer,Symbol]
|
|
260
|
+
# - The lock request priority: an Integer from `-100` (the lowest) to `100` (the highest),
|
|
261
|
+
# `0` by default (`RedisQueuedLocks::Resource::MIN_LOCK_PRIORITY`..`MAX_LOCK_PRIORITY`),
|
|
262
|
+
# or a priority name of `config['lock_priorities']` (`:lowest` (-100), `:low` (-50),
|
|
263
|
+
# `:normal` (0), `:high` (50), `:highest` (100) by default; the application can define its
|
|
264
|
+
# own names, `merge` keeps the default ones:
|
|
265
|
+
# `config['lock_priorities'] = config['lock_priorities'].merge(payment: 90, email: -10)`);
|
|
266
|
+
# - `:queued` access strategy: the lock request is placed in the lock request queue after all
|
|
267
|
+
# requests of the same or higher priority and before all requests of the lower priority
|
|
268
|
+
# (strict priority, FIFO inside the same priority; read and write lock requests too);
|
|
269
|
+
# - `:random` access strategy: the lock request does not wait for its turn (it ignores the order
|
|
270
|
+
# of the lock request queues and the priorities of other requests), but it is queued at the
|
|
271
|
+
# position of its priority like a `:queued` one: `:queued` lock requests wait for it;
|
|
272
|
+
# - the obtained lock is never taken away: the priority orders the waiting lock requests;
|
|
273
|
+
# - positive priorities need all processes that share the lock on RQL versions with priorities
|
|
274
|
+
# (older versions drop such lock requests as dead ones: the order is broken, the mutual
|
|
275
|
+
# exclusion is not affected); `0` and negative priorities work with older versions too;
|
|
276
|
+
# - pre-configured in `config['default_lock_priority']`;
|
|
250
277
|
# @option meta [NilClass,Hash<String|Symbol,Any>]
|
|
251
278
|
# - A custom metadata wich will be passed to the lock data in addition to the existing data;
|
|
252
279
|
# - Metadata can not contain reserved lock data keys;
|
|
@@ -283,8 +310,8 @@ class RedisQueuedLocks::Client
|
|
|
283
310
|
# - Custom instrumenter that will be invoked via #notify method with `event` and `payload` data;
|
|
284
311
|
# - See RedisQueuedLocks::Instrument::ActiveSupport for examples and implementation details;
|
|
285
312
|
# - See [Instrumentation](#instrumentation) section of docs;
|
|
286
|
-
# - pre-configured in `config['
|
|
287
|
-
# (`RedisQueuedLocks::
|
|
313
|
+
# - pre-configured in `config['instrumenter']` with void notifier
|
|
314
|
+
# (`RedisQueuedLocks::Instrument::VoidNotifier`);
|
|
288
315
|
# @option instrument [NilClass,Any]
|
|
289
316
|
# - Custom instrumentation data wich will be passed to the instrumenter's payload
|
|
290
317
|
# with :instrument key;
|
|
@@ -294,7 +321,7 @@ class RedisQueuedLocks::Client
|
|
|
294
321
|
# - works in tandem with <config['log_sampling_percent'] and <config['log_sampler']>;
|
|
295
322
|
# @option log_sampling_percent [Integer]
|
|
296
323
|
# - the percent of cases that should be logged;
|
|
297
|
-
# - take an effect when <config['
|
|
324
|
+
# - take an effect when <config['log_sampling_enabled']> is true;
|
|
298
325
|
# - works in tandem with <config['log_sampling_enabled']> and <config['log_sampler']> configs;
|
|
299
326
|
# @option log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
|
300
327
|
# - percent-based log sampler that decides should be RQL case logged or not;
|
|
@@ -315,7 +342,7 @@ class RedisQueuedLocks::Client
|
|
|
315
342
|
# - works in tandem with <config['instr_sampling_percent']> and <config['instr_sampler']>;
|
|
316
343
|
# @option instr_sampling_percent [Integer]
|
|
317
344
|
# - the percent of cases that should be instrumented;
|
|
318
|
-
# - take an effect when <config['
|
|
345
|
+
# - take an effect when <config['instr_sampling_enabled']> is true;
|
|
319
346
|
# - works in tandem with <config['instr_sampling_enabled']>
|
|
320
347
|
# and <config['instr_sampler']> configs;
|
|
321
348
|
# @option instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
|
@@ -339,7 +366,7 @@ class RedisQueuedLocks::Client
|
|
|
339
366
|
#
|
|
340
367
|
# @api public
|
|
341
368
|
# @since 1.0.0
|
|
342
|
-
# @version 1.
|
|
369
|
+
# @version 1.22.0
|
|
343
370
|
# rubocop:disable Metrics/MethodLength
|
|
344
371
|
def lock(
|
|
345
372
|
lock_name,
|
|
@@ -356,6 +383,7 @@ class RedisQueuedLocks::Client
|
|
|
356
383
|
conflict_strategy: config['default_conflict_strategy'],
|
|
357
384
|
read_write_mode: :write,
|
|
358
385
|
access_strategy: config['default_access_strategy'],
|
|
386
|
+
priority: config['default_lock_priority'],
|
|
359
387
|
identity: uniq_identity,
|
|
360
388
|
meta: nil,
|
|
361
389
|
detailed_acq_timeout_error: config['detailed_acq_timeout_error'],
|
|
@@ -396,6 +424,8 @@ class RedisQueuedLocks::Client
|
|
|
396
424
|
conflict_strategy:,
|
|
397
425
|
read_write_mode:,
|
|
398
426
|
access_strategy:,
|
|
427
|
+
priority:,
|
|
428
|
+
lock_priorities: config['lock_priorities'],
|
|
399
429
|
meta:,
|
|
400
430
|
detailed_acq_timeout_error:,
|
|
401
431
|
logger:,
|
|
@@ -415,10 +445,10 @@ class RedisQueuedLocks::Client
|
|
|
415
445
|
# rubocop:enable Metrics/MethodLength
|
|
416
446
|
|
|
417
447
|
# NOTE: Lock Series PoC
|
|
418
|
-
# rubocop:disable
|
|
448
|
+
# rubocop:disable Metrics/MethodLength
|
|
419
449
|
# @api public
|
|
420
450
|
# @since 1.16.0
|
|
421
|
-
# @version 1.
|
|
451
|
+
# @version 1.22.0
|
|
422
452
|
def lock_series( # steep:ignore
|
|
423
453
|
*lock_names,
|
|
424
454
|
detailed_result: false,
|
|
@@ -435,6 +465,7 @@ class RedisQueuedLocks::Client
|
|
|
435
465
|
conflict_strategy: config['default_conflict_strategy'],
|
|
436
466
|
read_write_mode: :write,
|
|
437
467
|
access_strategy: config['default_access_strategy'],
|
|
468
|
+
priority: config['default_lock_priority'],
|
|
438
469
|
identity: uniq_identity,
|
|
439
470
|
meta: nil,
|
|
440
471
|
detailed_acq_timeout_error: config['detailed_acq_timeout_error'],
|
|
@@ -476,6 +507,8 @@ class RedisQueuedLocks::Client
|
|
|
476
507
|
conflict_strategy:,
|
|
477
508
|
read_write_mode:,
|
|
478
509
|
access_strategy:,
|
|
510
|
+
priority:,
|
|
511
|
+
lock_priorities: config['lock_priorities'],
|
|
479
512
|
meta:,
|
|
480
513
|
detailed_acq_timeout_error:,
|
|
481
514
|
logger:,
|
|
@@ -492,13 +525,13 @@ class RedisQueuedLocks::Client
|
|
|
492
525
|
&block
|
|
493
526
|
)
|
|
494
527
|
end
|
|
495
|
-
# rubocop:enable
|
|
528
|
+
# rubocop:enable Metrics/MethodLength
|
|
496
529
|
|
|
497
530
|
# NOTE: Lock Series PoC
|
|
498
|
-
# rubocop:disable
|
|
531
|
+
# rubocop:disable Metrics/MethodLength
|
|
499
532
|
# @api public
|
|
500
533
|
# @since 1.16.0
|
|
501
|
-
# @version 1.
|
|
534
|
+
# @version 1.22.0
|
|
502
535
|
def lock_series!( # steep:ignore
|
|
503
536
|
*lock_names,
|
|
504
537
|
detailed_result: false,
|
|
@@ -514,6 +547,7 @@ class RedisQueuedLocks::Client
|
|
|
514
547
|
conflict_strategy: config['default_conflict_strategy'],
|
|
515
548
|
read_write_mode: :write,
|
|
516
549
|
access_strategy: config['default_access_strategy'],
|
|
550
|
+
priority: config['default_lock_priority'],
|
|
517
551
|
identity: uniq_identity,
|
|
518
552
|
meta: nil,
|
|
519
553
|
detailed_acq_timeout_error: config['detailed_acq_timeout_error'],
|
|
@@ -547,6 +581,7 @@ class RedisQueuedLocks::Client
|
|
|
547
581
|
conflict_strategy:,
|
|
548
582
|
read_write_mode:,
|
|
549
583
|
access_strategy:,
|
|
584
|
+
priority:,
|
|
550
585
|
identity:,
|
|
551
586
|
meta:,
|
|
552
587
|
detailed_acq_timeout_error:,
|
|
@@ -565,12 +600,14 @@ class RedisQueuedLocks::Client
|
|
|
565
600
|
&block
|
|
566
601
|
)
|
|
567
602
|
end
|
|
603
|
+
# rubocop:enable Metrics/MethodLength
|
|
568
604
|
|
|
569
605
|
# @note See #lock method signature.
|
|
570
606
|
#
|
|
607
|
+
# rubocop:disable Metrics/MethodLength
|
|
571
608
|
# @api public
|
|
572
609
|
# @since 1.0.0
|
|
573
|
-
# @version 1.
|
|
610
|
+
# @version 1.22.0
|
|
574
611
|
def lock!(
|
|
575
612
|
lock_name,
|
|
576
613
|
ttl: config['default_lock_ttl'],
|
|
@@ -585,6 +622,7 @@ class RedisQueuedLocks::Client
|
|
|
585
622
|
conflict_strategy: config['default_conflict_strategy'],
|
|
586
623
|
read_write_mode: :write,
|
|
587
624
|
access_strategy: config['default_access_strategy'],
|
|
625
|
+
priority: config['default_lock_priority'],
|
|
588
626
|
identity: uniq_identity,
|
|
589
627
|
instrumenter: config['instrumenter'],
|
|
590
628
|
meta: nil,
|
|
@@ -624,6 +662,7 @@ class RedisQueuedLocks::Client
|
|
|
624
662
|
conflict_strategy:,
|
|
625
663
|
read_write_mode:,
|
|
626
664
|
access_strategy:,
|
|
665
|
+
priority:,
|
|
627
666
|
log_sampling_enabled:,
|
|
628
667
|
log_sampling_percent:,
|
|
629
668
|
log_sampler:,
|
|
@@ -665,7 +704,7 @@ class RedisQueuedLocks::Client
|
|
|
665
704
|
#
|
|
666
705
|
# @api public
|
|
667
706
|
# @since 1.0.0
|
|
668
|
-
# @version 1.
|
|
707
|
+
# @version 1.21.0
|
|
669
708
|
def unlock(
|
|
670
709
|
lock_name,
|
|
671
710
|
logger: config['logger'],
|
|
@@ -684,8 +723,9 @@ class RedisQueuedLocks::Client
|
|
|
684
723
|
redis_client,
|
|
685
724
|
lock_name,
|
|
686
725
|
config['lock_index_enabled'],
|
|
687
|
-
instrumenter,
|
|
688
726
|
logger,
|
|
727
|
+
instrumenter,
|
|
728
|
+
instrument,
|
|
689
729
|
log_sampling_enabled,
|
|
690
730
|
log_sampling_percent,
|
|
691
731
|
log_sampler,
|
|
@@ -705,13 +745,15 @@ class RedisQueuedLocks::Client
|
|
|
705
745
|
#
|
|
706
746
|
# @param lock_name [String] The lock name whose read lock should be released.
|
|
707
747
|
# @option acquirer_id [String,NilClass]
|
|
708
|
-
# -
|
|
709
|
-
# - `nil` => the current acquirer is used (calculated from `identity:`,
|
|
710
|
-
#
|
|
748
|
+
# - the acquirer whose read lock should be released (`nil` by default);
|
|
749
|
+
# - `nil` => the current acquirer is used (calculated from `identity:`,
|
|
750
|
+
# see `#current_acquirer_id`);
|
|
751
|
+
# - can be extracted from the lock data (`#lock_info`, `#locks_info`, `#queue_info`,
|
|
752
|
+
# `#queues_info`);
|
|
711
753
|
# @option identity [String]
|
|
712
754
|
# Unique acquirer identity (the same as for `#lock`) that is used to calculate the current
|
|
713
|
-
# acquirer id (see `#current_acquirer_id`). Ignored when `acquirer_id:` is passed: the
|
|
714
|
-
# already contains its own identity.
|
|
755
|
+
# acquirer id (see `#current_acquirer_id`). Ignored when `acquirer_id:` is passed: the
|
|
756
|
+
# acquirer id already contains its own identity.
|
|
715
757
|
# @option logger [::Logger,#debug]
|
|
716
758
|
# @option instrumenter [#notify]
|
|
717
759
|
# @option instrument [NilClass,Any]
|
|
@@ -742,7 +784,7 @@ class RedisQueuedLocks::Client
|
|
|
742
784
|
#
|
|
743
785
|
# @api public
|
|
744
786
|
# @since 1.18.0
|
|
745
|
-
# @version 1.
|
|
787
|
+
# @version 1.21.0
|
|
746
788
|
def unlock_read(
|
|
747
789
|
lock_name,
|
|
748
790
|
acquirer_id: nil,
|
|
@@ -763,8 +805,8 @@ class RedisQueuedLocks::Client
|
|
|
763
805
|
redis_client,
|
|
764
806
|
lock_name,
|
|
765
807
|
acquirer_id || current_acquirer_id(identity:),
|
|
766
|
-
instrumenter,
|
|
767
808
|
logger,
|
|
809
|
+
instrumenter,
|
|
768
810
|
instrument,
|
|
769
811
|
log_sampling_enabled,
|
|
770
812
|
log_sampling_percent,
|
|
@@ -817,7 +859,7 @@ class RedisQueuedLocks::Client
|
|
|
817
859
|
#
|
|
818
860
|
# @api public
|
|
819
861
|
# @since 1.0.0
|
|
820
|
-
# @version 1.
|
|
862
|
+
# @version 1.22.0
|
|
821
863
|
def queue_info(lock_name)
|
|
822
864
|
RedisQueuedLocks::Acquirer::QueueInfo.queue_info(redis_client, lock_name)
|
|
823
865
|
end
|
|
@@ -902,19 +944,14 @@ class RedisQueuedLocks::Client
|
|
|
902
944
|
RedisQueuedLocks::Resource.possible_host_identifiers(identity)
|
|
903
945
|
end
|
|
904
946
|
|
|
905
|
-
#
|
|
906
|
-
#
|
|
907
|
-
#
|
|
908
|
-
# (2) set new ttl that is calculated as "current pttl + additional milliseconds"
|
|
909
|
-
# What can happen during these steps
|
|
910
|
-
# - lock is expired between commands or before the first command;
|
|
911
|
-
# - lock is expired before the second command;
|
|
912
|
-
# - lock is expired AND newly acquired by another process (so you will extend the
|
|
913
|
-
# totally new lock with fresh PTTL);
|
|
947
|
+
# The write lock TTL is extended atomically by one Lua script (`PTTL` + `PEXPIRE` with
|
|
948
|
+
# "current pttl + additional milliseconds") without the lock owner check: when your lock is
|
|
949
|
+
# expired and newly obtained by another acquirer, the lock of that acquirer is extended.
|
|
914
950
|
# Use it at your own risk and consider async nature when calling this method.
|
|
915
951
|
#
|
|
916
952
|
# @param lock_name [String]
|
|
917
|
-
# @param milliseconds [Integer]
|
|
953
|
+
# @param milliseconds [Integer]
|
|
954
|
+
# How many milliseconds should be added: a positive Integer.
|
|
918
955
|
# @option read_write_mode [Symbol]
|
|
919
956
|
# - `:write` (default) - extends the write lock (the method description above);
|
|
920
957
|
# - `:read` - extends the read lock of the current acquirer only (an expired read lock or
|
|
@@ -944,7 +981,7 @@ class RedisQueuedLocks::Client
|
|
|
944
981
|
#
|
|
945
982
|
# @api public
|
|
946
983
|
# @since 1.0.0
|
|
947
|
-
# @version 1.
|
|
984
|
+
# @version 1.21.0
|
|
948
985
|
def extend_lock_ttl(
|
|
949
986
|
lock_name,
|
|
950
987
|
milliseconds,
|
|
@@ -1008,7 +1045,7 @@ class RedisQueuedLocks::Client
|
|
|
1008
1045
|
#
|
|
1009
1046
|
# @api public
|
|
1010
1047
|
# @since 1.0.0
|
|
1011
|
-
# @version 1.
|
|
1048
|
+
# @version 1.21.0
|
|
1012
1049
|
def clear_locks(
|
|
1013
1050
|
batch_size: config['lock_release_batch_size'],
|
|
1014
1051
|
logger: config['logger'],
|
|
@@ -1097,12 +1134,12 @@ class RedisQueuedLocks::Client
|
|
|
1097
1134
|
#
|
|
1098
1135
|
# @api public
|
|
1099
1136
|
# @since 1.14.0
|
|
1100
|
-
# @version 1.
|
|
1137
|
+
# @version 1.21.0
|
|
1101
1138
|
def clear_locks_of(
|
|
1102
1139
|
host_id:,
|
|
1103
1140
|
acquirer_id:,
|
|
1104
1141
|
lock_scan_size: config['clear_locks_of__lock_scan_size'],
|
|
1105
|
-
queue_scan_size: config['clear_locks_of__queue_scan_size'],
|
|
1142
|
+
queue_scan_size: config['clear_locks_of__queue_scan_size'],
|
|
1106
1143
|
logger: config['logger'],
|
|
1107
1144
|
instrumenter: config['instrumenter'],
|
|
1108
1145
|
instrument: nil,
|
|
@@ -1140,7 +1177,8 @@ class RedisQueuedLocks::Client
|
|
|
1140
1177
|
# Release all locks of the current acquirer/host and
|
|
1141
1178
|
# remove the current acquirer/host from all queues;
|
|
1142
1179
|
#
|
|
1143
|
-
# @option
|
|
1180
|
+
# @option lock_scan_size [Integer]
|
|
1181
|
+
# @option queue_scan_size [Integer]
|
|
1144
1182
|
# @option logger [::Logger,#debug]
|
|
1145
1183
|
# @option instrumenter [#notify] See `config['instrumenter']` docs for details.
|
|
1146
1184
|
# @option instrument [NilClass,Any]
|
|
@@ -1159,9 +1197,10 @@ class RedisQueuedLocks::Client
|
|
|
1159
1197
|
#
|
|
1160
1198
|
# @api public
|
|
1161
1199
|
# @since 1.14.0
|
|
1200
|
+
# @version 1.21.0
|
|
1162
1201
|
def clear_current_locks(
|
|
1163
1202
|
lock_scan_size: config['clear_locks_of__lock_scan_size'],
|
|
1164
|
-
queue_scan_size: config['clear_locks_of__queue_scan_size'],
|
|
1203
|
+
queue_scan_size: config['clear_locks_of__queue_scan_size'],
|
|
1165
1204
|
logger: config['logger'],
|
|
1166
1205
|
instrumenter: config['instrumenter'],
|
|
1167
1206
|
instrument: nil,
|
|
@@ -1216,7 +1255,7 @@ class RedisQueuedLocks::Client
|
|
|
1216
1255
|
#
|
|
1217
1256
|
# @api public
|
|
1218
1257
|
# @since 1.0.0
|
|
1219
|
-
# @version 1.
|
|
1258
|
+
# @version 1.21.0
|
|
1220
1259
|
def locks(scan_size: config['key_extraction_batch_size'], with_info: false)
|
|
1221
1260
|
RedisQueuedLocks::Acquirer::Locks.locks(
|
|
1222
1261
|
redis_client, scan_size:, with_info:, lock_index_enabled: config['lock_index_enabled']
|
|
@@ -1230,8 +1269,9 @@ class RedisQueuedLocks::Client
|
|
|
1230
1269
|
#
|
|
1231
1270
|
# @api public
|
|
1232
1271
|
# @since 1.0.0
|
|
1233
|
-
|
|
1234
|
-
|
|
1272
|
+
# @version 1.21.0
|
|
1273
|
+
def locks_info(scan_size: config['key_extraction_batch_size'])
|
|
1274
|
+
locks(scan_size:, with_info: true) #: RedisQueuedLocks::Acquirer::Locks::locksInfo
|
|
1235
1275
|
end
|
|
1236
1276
|
|
|
1237
1277
|
# @option scan_size [Integer]
|
|
@@ -1253,7 +1293,7 @@ class RedisQueuedLocks::Client
|
|
|
1253
1293
|
#
|
|
1254
1294
|
# @api public
|
|
1255
1295
|
# @since 1.0.0
|
|
1256
|
-
# @version 1.
|
|
1296
|
+
# @version 1.22.0
|
|
1257
1297
|
def queues(scan_size: config['key_extraction_batch_size'], with_info: false)
|
|
1258
1298
|
RedisQueuedLocks::Acquirer::Queues.queues(
|
|
1259
1299
|
redis_client, scan_size:, with_info:, lock_index_enabled: config['lock_index_enabled']
|
|
@@ -1267,8 +1307,9 @@ class RedisQueuedLocks::Client
|
|
|
1267
1307
|
#
|
|
1268
1308
|
# @api public
|
|
1269
1309
|
# @since 1.0.0
|
|
1310
|
+
# @version 1.22.0
|
|
1270
1311
|
def queues_info(scan_size: config['key_extraction_batch_size'])
|
|
1271
|
-
queues(scan_size:, with_info: true)
|
|
1312
|
+
queues(scan_size:, with_info: true) #: RedisQueuedLocks::Acquirer::Queues::queuesInfo
|
|
1272
1313
|
end
|
|
1273
1314
|
|
|
1274
1315
|
# @option scan_size [Integer]
|
|
@@ -1279,7 +1320,7 @@ class RedisQueuedLocks::Client
|
|
|
1279
1320
|
#
|
|
1280
1321
|
# @api public
|
|
1281
1322
|
# @since 1.0.0
|
|
1282
|
-
# @version 1.
|
|
1323
|
+
# @version 1.21.0
|
|
1283
1324
|
def keys(scan_size: config['key_extraction_batch_size'])
|
|
1284
1325
|
RedisQueuedLocks::Acquirer::Keys.keys(
|
|
1285
1326
|
redis_client, scan_size:, lock_index_enabled: config['lock_index_enabled']
|
|
@@ -1294,6 +1335,13 @@ class RedisQueuedLocks::Client
|
|
|
1294
1335
|
# - the batch of scanned keys for Redis'es SCAN command (or the number of locks in one batch of
|
|
1295
1336
|
# the lock index ZSCAN pass: the enabled `config['lock_index_enabled']`);
|
|
1296
1337
|
# - `config['lock_release_batch_size']` is used by default;
|
|
1338
|
+
# @option by_priority [Boolean]
|
|
1339
|
+
# - read only the first lock request of each priority in the lock queues instead of all lock
|
|
1340
|
+
# requests (the dead requests of a priority are found by its first lock request): the
|
|
1341
|
+
# transfer does not depend on the length of the lock queues, a batch of lock queues takes
|
|
1342
|
+
# one round trip per priority of its lock queue with the most priorities + 1 (instead of two
|
|
1343
|
+
# round trips): for long lock queues with few priorities;
|
|
1344
|
+
# - `false` by default (all lock requests are read);
|
|
1297
1345
|
# @option logger [::Logger,#debug]
|
|
1298
1346
|
# @option instrumenter [#notify]
|
|
1299
1347
|
# @option instrument [NilClass,Any]
|
|
@@ -1310,10 +1358,11 @@ class RedisQueuedLocks::Client
|
|
|
1310
1358
|
#
|
|
1311
1359
|
# @api public
|
|
1312
1360
|
# @since 1.0.0
|
|
1313
|
-
# @version 1.
|
|
1361
|
+
# @version 1.22.0
|
|
1314
1362
|
def clear_dead_requests(
|
|
1315
1363
|
dead_ttl: config['dead_request_ttl'],
|
|
1316
1364
|
scan_size: config['lock_release_batch_size'],
|
|
1365
|
+
by_priority: false,
|
|
1317
1366
|
logger: config['logger'],
|
|
1318
1367
|
instrumenter: config['instrumenter'],
|
|
1319
1368
|
instrument: nil,
|
|
@@ -1330,6 +1379,7 @@ class RedisQueuedLocks::Client
|
|
|
1330
1379
|
redis_client,
|
|
1331
1380
|
scan_size,
|
|
1332
1381
|
dead_ttl,
|
|
1382
|
+
by_priority,
|
|
1333
1383
|
config['lock_index_enabled'],
|
|
1334
1384
|
logger,
|
|
1335
1385
|
instrumenter,
|
|
@@ -1346,8 +1396,8 @@ class RedisQueuedLocks::Client
|
|
|
1346
1396
|
end
|
|
1347
1397
|
|
|
1348
1398
|
# Adds the lock keys without the lock index entry (keys of older RQL versions, keys created while
|
|
1349
|
-
# the lock index was disabled) to the lock index (`rql:index:locks`). Invoke it once after the
|
|
1350
|
-
# index is enabled (`config['lock_index_enabled']`) on all your processes: lock-iterating
|
|
1399
|
+
# the lock index was disabled) to the lock index (`rql:index:locks`). Invoke it once after the
|
|
1400
|
+
# lock index is enabled (`config['lock_index_enabled']`) on all your processes: lock-iterating
|
|
1351
1401
|
# operations (the swarm, `#locks`, `#queues`, `#keys`, `#clear_locks`, ...) find locks via
|
|
1352
1402
|
# the lock index only.
|
|
1353
1403
|
# - works regardless of `config['lock_index_enabled']` (the lock index is not used and not
|
|
@@ -1365,21 +1415,55 @@ class RedisQueuedLocks::Client
|
|
|
1365
1415
|
# @option lock_index_grace_period [Integer]
|
|
1366
1416
|
# - the lock index score margin over the key lifetime (in milliseconds);
|
|
1367
1417
|
# - `config['lock_index_grace_period']` is used by default;
|
|
1418
|
+
# @option logger [::Logger,#debug]
|
|
1419
|
+
# @option instrumenter [#notify]
|
|
1420
|
+
# @option instrument [NilClass,Any]
|
|
1421
|
+
# @option log_sampling_enabled [Boolean]
|
|
1422
|
+
# @option log_sampling_percent [Integer]
|
|
1423
|
+
# @option log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
|
1424
|
+
# @option log_sample_this [Boolean]
|
|
1425
|
+
# @option instr_sampling_enabled [Boolean]
|
|
1426
|
+
# @option instr_sampling_percent [Integer]
|
|
1427
|
+
# @option instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
|
1428
|
+
# @option instr_sample_this [Boolean]
|
|
1368
1429
|
# @return [Hash<Symbol,Boolean|Hash<Symbol,Integer>>]
|
|
1369
1430
|
# Format: { ok: true, result: { idx_key_cnt: Integer } } (the number of indexed keys)
|
|
1370
1431
|
#
|
|
1371
1432
|
# @api public
|
|
1372
1433
|
# @since 1.20.0
|
|
1434
|
+
# @version 1.21.0
|
|
1373
1435
|
def reindex_locks(
|
|
1374
1436
|
scan_size: config['lock_release_batch_size'],
|
|
1375
1437
|
queue_ttl: config['default_queue_ttl'],
|
|
1376
|
-
lock_index_grace_period: config['lock_index_grace_period']
|
|
1438
|
+
lock_index_grace_period: config['lock_index_grace_period'],
|
|
1439
|
+
logger: config['logger'],
|
|
1440
|
+
instrumenter: config['instrumenter'],
|
|
1441
|
+
instrument: nil,
|
|
1442
|
+
log_sampling_enabled: config['log_sampling_enabled'],
|
|
1443
|
+
log_sampling_percent: config['log_sampling_percent'],
|
|
1444
|
+
log_sampler: config['log_sampler'],
|
|
1445
|
+
log_sample_this: false,
|
|
1446
|
+
instr_sampling_enabled: config['instr_sampling_enabled'],
|
|
1447
|
+
instr_sampling_percent: config['instr_sampling_percent'],
|
|
1448
|
+
instr_sampler: config['instr_sampler'],
|
|
1449
|
+
instr_sample_this: false
|
|
1377
1450
|
)
|
|
1378
1451
|
RedisQueuedLocks::Acquirer::ReindexLocks.reindex_locks(
|
|
1379
1452
|
redis_client,
|
|
1380
1453
|
scan_size,
|
|
1381
1454
|
queue_ttl,
|
|
1382
|
-
lock_index_grace_period
|
|
1455
|
+
lock_index_grace_period,
|
|
1456
|
+
logger,
|
|
1457
|
+
instrumenter,
|
|
1458
|
+
instrument,
|
|
1459
|
+
log_sampling_enabled,
|
|
1460
|
+
log_sampling_percent,
|
|
1461
|
+
log_sampler,
|
|
1462
|
+
log_sample_this,
|
|
1463
|
+
instr_sampling_enabled,
|
|
1464
|
+
instr_sampling_percent,
|
|
1465
|
+
instr_sampler,
|
|
1466
|
+
instr_sample_this
|
|
1383
1467
|
)
|
|
1384
1468
|
end
|
|
1385
1469
|
end
|