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.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/project-overview.md +249 -36
  3. data/.claude/rules/acquirer.md +16 -14
  4. data/.claude/rules/arguments.md +2 -2
  5. data/.claude/rules/changelog.md +27 -0
  6. data/.claude/rules/git.md +1 -1
  7. data/.claude/rules/logic.md +34 -13
  8. data/.claude/rules/swarm.md +4 -5
  9. data/.claude/rules/tests.md +9 -6
  10. data/.claude/rules/type-checking.md +13 -14
  11. data/.claude/rules/visitors.md +13 -14
  12. data/.claude/skills/rql-code-review/SKILL.md +134 -43
  13. data/CHANGELOG.md +105 -125
  14. data/CLAUDE.md +11 -9
  15. data/README.md +501 -136
  16. data/Rakefile +11 -0
  17. data/lib/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +1 -0
  18. data/lib/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rb +68 -10
  19. data/lib/redis_queued_locks/acquirer/acquire_lock/log_visitor.rb +82 -15
  20. data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rb +92 -14
  21. data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rb +441 -63
  22. data/lib/redis_queued_locks/acquirer/acquire_lock/with_acq_timeout.rb +2 -2
  23. data/lib/redis_queued_locks/acquirer/acquire_lock/yield_expire/log_visitor.rb +1 -0
  24. data/lib/redis_queued_locks/acquirer/acquire_lock/yield_expire.rb +5 -5
  25. data/lib/redis_queued_locks/acquirer/acquire_lock.rb +176 -39
  26. data/lib/redis_queued_locks/acquirer/clear_dead_requests.rb +322 -49
  27. data/lib/redis_queued_locks/acquirer/extend_lock_ttl.rb +125 -13
  28. data/lib/redis_queued_locks/acquirer/is_locked.rb +0 -1
  29. data/lib/redis_queued_locks/acquirer/is_queued.rb +0 -1
  30. data/lib/redis_queued_locks/acquirer/keys.rb +16 -3
  31. data/lib/redis_queued_locks/acquirer/lock_info.rb +31 -39
  32. data/lib/redis_queued_locks/acquirer/lock_series_poc/instr_visitor.rb +11 -5
  33. data/lib/redis_queued_locks/acquirer/lock_series_poc/log_visitor.rb +20 -10
  34. data/lib/redis_queued_locks/acquirer/lock_series_poc.rb +105 -36
  35. data/lib/redis_queued_locks/acquirer/locks.rb +32 -11
  36. data/lib/redis_queued_locks/acquirer/queue_info.rb +30 -8
  37. data/lib/redis_queued_locks/acquirer/queues.rb +26 -6
  38. data/lib/redis_queued_locks/acquirer/reindex_locks.rb +117 -4
  39. data/lib/redis_queued_locks/acquirer/release_all_locks.rb +37 -6
  40. data/lib/redis_queued_locks/acquirer/release_lock.rb +33 -7
  41. data/lib/redis_queued_locks/acquirer/release_locks_of.rb +45 -6
  42. data/lib/redis_queued_locks/acquirer/release_read_lock.rb +22 -3
  43. data/lib/redis_queued_locks/client.rb +140 -56
  44. data/lib/redis_queued_locks/config.rb +105 -14
  45. data/lib/redis_queued_locks/errors.rb +34 -4
  46. data/lib/redis_queued_locks/instrument/sampler.rb +4 -7
  47. data/lib/redis_queued_locks/logging/sampler.rb +4 -8
  48. data/lib/redis_queued_locks/resource.rb +137 -12
  49. data/lib/redis_queued_locks/swarm/flush_zombies.rb +1 -0
  50. data/lib/redis_queued_locks/swarm/redis_client_builder.rb +8 -4
  51. data/lib/redis_queued_locks/swarm/swarm_element/threaded.rb +8 -6
  52. data/lib/redis_queued_locks/swarm/zombie_info.rb +6 -2
  53. data/lib/redis_queued_locks/swarm.rb +86 -5
  54. data/lib/redis_queued_locks/utilities.rb +1 -1
  55. data/lib/redis_queued_locks/version.rb +2 -2
  56. data/rbs_collection.lock.yaml +4 -0
  57. data/rbs_collection.yaml +2 -1
  58. data/sig/manifest.yml +1 -0
  59. data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rbs +2 -2
  60. data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue.rbs +2 -2
  61. data/sig/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rbs +25 -5
  62. data/sig/redis_queued_locks/acquirer/acquire_lock/log_visitor.rbs +32 -12
  63. data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rbs +61 -40
  64. data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rbs +59 -11
  65. data/sig/redis_queued_locks/acquirer/acquire_lock/{yield_with_expire → yield_expire}/log_visitor.rbs +4 -4
  66. data/sig/redis_queued_locks/acquirer/acquire_lock/yield_expire.rbs +4 -4
  67. data/sig/redis_queued_locks/acquirer/acquire_lock.rbs +6 -4
  68. data/sig/redis_queued_locks/acquirer/clear_dead_requests.rbs +23 -1
  69. data/sig/redis_queued_locks/acquirer/extend_lock_ttl.rbs +16 -3
  70. data/sig/redis_queued_locks/acquirer/queues.rbs +1 -1
  71. data/sig/redis_queued_locks/acquirer/reindex_locks.rbs +22 -1
  72. data/sig/redis_queued_locks/acquirer/release_lock.rbs +3 -2
  73. data/sig/redis_queued_locks/acquirer/release_read_lock.rbs +1 -1
  74. data/sig/redis_queued_locks/client.rbs +24 -10
  75. data/sig/redis_queued_locks/config.rbs +54 -1
  76. data/sig/redis_queued_locks/errors.rbs +5 -2
  77. data/sig/redis_queued_locks/instrument/sampler.rbs +3 -3
  78. data/sig/redis_queued_locks/instrument/void_notifier.rbs +3 -1
  79. data/sig/redis_queued_locks/logging/sampler.rbs +3 -3
  80. data/sig/redis_queued_locks/resource.rbs +23 -13
  81. data/sig/redis_queued_locks/swarm/swarm_element/threaded.rbs +1 -1
  82. data/sig/redis_queued_locks/utilities.rbs +2 -1
  83. data/sig/redis_queued_locks.rbs +7 -0
  84. data/sig/vendor/redis_client.rbs +1 -0
  85. metadata +4 -3
  86. /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.20.0
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 #: String
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 ppublic
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.17.0
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 ignores lock queues (a continuous flow of readers can starve
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['isntrumenter']` with void notifier
287
- # (`RedisQueuedLocks::Instrumenter::VoidNotifier`);
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['log_sampling_enalbed']> is true;
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['instr_sampling_enalbed']> is true;
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.20.0
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 all
448
+ # rubocop:disable Metrics/MethodLength
419
449
  # @api public
420
450
  # @since 1.16.0
421
- # @version 1.20.0
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 all
528
+ # rubocop:enable Metrics/MethodLength
496
529
 
497
530
  # NOTE: Lock Series PoC
498
- # rubocop:disable all
531
+ # rubocop:disable Metrics/MethodLength
499
532
  # @api public
500
533
  # @since 1.16.0
501
- # @version 1.20.0
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.20.0
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.20.0
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
- # - The acquirer whose read lock should be released (`nil` by default);
709
- # - `nil` => the current acquirer is used (calculated from `identity:`, see `#current_acquirer_id`);
710
- # - can be extracted from the lock data (`#lock_info`, `#locks_info`, `#queue_info`, `#queues_info`);
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 acquirer id
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.19.0
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.18.0
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
- # This method is non-atomic cuz redis does not provide an atomic function for TTL/PTTL extension.
906
- # So the methid is spliited into the two commands:
907
- # (1) read current pttl
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] How many milliseconds should be added.
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.20.0
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.20.0
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.20.0
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'], # steep:ingore
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 batch_size [Integer]
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'], # steep:ingore
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.20.0
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
- def locks_info(scan_size: config['key_extraction_batch_size']) # steep:ignore
1234
- locks(scan_size:, with_info: true)
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.20.0
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.20.0
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.20.0
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 lock
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