redis_queued_locks 1.19.0 → 1.21.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 +96 -23
- data/.claude/rules/acquirer.md +39 -20
- data/.claude/rules/arguments.md +3 -2
- data/.claude/rules/git.md +3 -2
- data/.claude/rules/logic.md +32 -8
- data/.claude/rules/swarm.md +14 -9
- data/.claude/rules/tests.md +12 -3
- data/.claude/rules/type-checking.md +2 -1
- data/.claude/rules/visitors.md +10 -11
- data/.claude/skills/rql-code-review/SKILL.md +386 -0
- data/.claude/skills/rql-code-review/templates/report.en.md +31 -0
- data/.claude/skills/rql-code-review/templates/report.ru.md +31 -0
- data/CHANGELOG.md +194 -0
- data/CLAUDE.md +6 -3
- data/README.md +502 -92
- 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 +42 -0
- data/lib/redis_queued_locks/acquirer/acquire_lock/log_visitor.rb +45 -0
- data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rb +1 -0
- data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rb +695 -128
- 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 +8 -6
- data/lib/redis_queued_locks/acquirer/acquire_lock.rb +134 -26
- data/lib/redis_queued_locks/acquirer/clear_dead_requests.rb +229 -24
- data/lib/redis_queued_locks/acquirer/extend_lock_ttl.rb +189 -18
- 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 +151 -7
- data/lib/redis_queued_locks/acquirer/lock_info.rb +39 -41
- data/lib/redis_queued_locks/acquirer/lock_series_poc/instr_visitor.rb +3 -2
- data/lib/redis_queued_locks/acquirer/lock_series_poc/log_visitor.rb +5 -4
- data/lib/redis_queued_locks/acquirer/lock_series_poc.rb +79 -20
- data/lib/redis_queued_locks/acquirer/locks.rb +212 -83
- data/lib/redis_queued_locks/acquirer/queue_info.rb +11 -18
- data/lib/redis_queued_locks/acquirer/queues.rb +123 -50
- data/lib/redis_queued_locks/acquirer/reindex_locks.rb +253 -0
- data/lib/redis_queued_locks/acquirer/release_all_locks.rb +177 -61
- data/lib/redis_queued_locks/acquirer/release_lock.rb +84 -25
- data/lib/redis_queued_locks/acquirer/release_locks_of.rb +274 -70
- data/lib/redis_queued_locks/acquirer/release_read_lock.rb +22 -3
- data/lib/redis_queued_locks/acquirer.rb +1 -0
- data/lib/redis_queued_locks/client.rb +164 -36
- data/lib/redis_queued_locks/config.rb +16 -13
- 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 +113 -6
- data/lib/redis_queued_locks/swarm/flush_zombies.rb +333 -61
- data/lib/redis_queued_locks/swarm/redis_client_builder.rb +8 -4
- data/lib/redis_queued_locks/swarm/swarm_element/threaded.rb +3 -2
- data/lib/redis_queued_locks/swarm/zombie_info.rb +203 -53
- data/lib/redis_queued_locks/swarm.rb +97 -5
- data/lib/redis_queued_locks/utilities.rb +1 -1
- data/lib/redis_queued_locks/version.rb +2 -2
- data/sig/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rbs +14 -0
- data/sig/redis_queued_locks/acquirer/acquire_lock/log_visitor.rbs +13 -0
- data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rbs +107 -1
- data/sig/redis_queued_locks/acquirer/acquire_lock/yield_expire.rbs +3 -3
- data/sig/redis_queued_locks/acquirer/acquire_lock.rbs +3 -1
- data/sig/redis_queued_locks/acquirer/clear_dead_requests.rbs +19 -1
- data/sig/redis_queued_locks/acquirer/extend_lock_ttl.rbs +20 -4
- data/sig/redis_queued_locks/acquirer/keys.rbs +11 -1
- data/sig/redis_queued_locks/acquirer/locks.rbs +15 -6
- data/sig/redis_queued_locks/acquirer/queues.rbs +9 -2
- data/sig/redis_queued_locks/acquirer/reindex_locks.rbs +52 -0
- data/sig/redis_queued_locks/acquirer/release_all_locks.rbs +8 -1
- data/sig/redis_queued_locks/acquirer/release_lock.rbs +6 -3
- data/sig/redis_queued_locks/acquirer/release_locks_of.rbs +20 -1
- data/sig/redis_queued_locks/acquirer/release_read_lock.rbs +1 -1
- data/sig/redis_queued_locks/client.rbs +21 -2
- data/sig/redis_queued_locks/errors.rbs +5 -2
- data/sig/redis_queued_locks/instrument/sampler.rbs +0 -2
- data/sig/redis_queued_locks/logging/sampler.rbs +0 -2
- data/sig/redis_queued_locks/resource.rbs +7 -1
- data/sig/redis_queued_locks/swarm/flush_zombies.rbs +51 -1
- data/sig/redis_queued_locks/swarm/zombie_info.rbs +58 -7
- data/sig/vendor/redis_client.rbs +2 -0
- metadata +6 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# @api public
|
|
4
4
|
# @since 1.0.0
|
|
5
|
-
# @version 1.
|
|
5
|
+
# @version 1.21.0
|
|
6
6
|
# rubocop:disable Metrics/ClassLength
|
|
7
7
|
class RedisQueuedLocks::Client
|
|
8
8
|
# @return [RedisClient]
|
|
@@ -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,11 +176,22 @@ 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.
|
|
184
|
+
# @option lock_index_grace_period [Integer]
|
|
185
|
+
# - The lock index score margin over the lock key lifetime (in milliseconds): the lock name
|
|
186
|
+
# stays in the lock index (`rql:index:locks`) for this period after the expiration of
|
|
187
|
+
# the lock keys;
|
|
188
|
+
# - should be greater than the client clock skew between your hosts plus the network latency;
|
|
189
|
+
# - used only with the enabled lock index (`config['lock_index_enabled']`, the client-wide
|
|
190
|
+
# mode: the lock index is maintained by all lock acquirements of the client);
|
|
191
|
+
# - pre-configured in `config['lock_index_grace_period']`;
|
|
177
192
|
# @option timeout [Integer,NilClass]
|
|
178
|
-
# 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`).
|
|
179
195
|
# @option timed [Boolean]
|
|
180
196
|
# Limit the invocation time period of the passed block of code by the lock's TTL.
|
|
181
197
|
# @option retry_count [Integer,NilClass]
|
|
@@ -286,7 +302,7 @@ class RedisQueuedLocks::Client
|
|
|
286
302
|
# - works in tandem with <config['log_sampling_percent'] and <config['log_sampler']>;
|
|
287
303
|
# @option log_sampling_percent [Integer]
|
|
288
304
|
# - the percent of cases that should be logged;
|
|
289
|
-
# - take an effect when <config['
|
|
305
|
+
# - take an effect when <config['log_sampling_enabled']> is true;
|
|
290
306
|
# - works in tandem with <config['log_sampling_enabled']> and <config['log_sampler']> configs;
|
|
291
307
|
# @option log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
|
292
308
|
# - percent-based log sampler that decides should be RQL case logged or not;
|
|
@@ -307,7 +323,7 @@ class RedisQueuedLocks::Client
|
|
|
307
323
|
# - works in tandem with <config['instr_sampling_percent']> and <config['instr_sampler']>;
|
|
308
324
|
# @option instr_sampling_percent [Integer]
|
|
309
325
|
# - the percent of cases that should be instrumented;
|
|
310
|
-
# - take an effect when <config['
|
|
326
|
+
# - take an effect when <config['instr_sampling_enabled']> is true;
|
|
311
327
|
# - works in tandem with <config['instr_sampling_enabled']>
|
|
312
328
|
# and <config['instr_sampler']> configs;
|
|
313
329
|
# @option instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
|
@@ -331,12 +347,13 @@ class RedisQueuedLocks::Client
|
|
|
331
347
|
#
|
|
332
348
|
# @api public
|
|
333
349
|
# @since 1.0.0
|
|
334
|
-
# @version 1.
|
|
350
|
+
# @version 1.21.0
|
|
335
351
|
# rubocop:disable Metrics/MethodLength
|
|
336
352
|
def lock(
|
|
337
353
|
lock_name,
|
|
338
354
|
ttl: config['default_lock_ttl'],
|
|
339
355
|
queue_ttl: config['default_queue_ttl'],
|
|
356
|
+
lock_index_grace_period: config['lock_index_grace_period'],
|
|
340
357
|
timeout: config['try_to_lock_timeout'],
|
|
341
358
|
timed: config['is_timed_by_default'],
|
|
342
359
|
retry_count: config['retry_count'],
|
|
@@ -373,6 +390,8 @@ class RedisQueuedLocks::Client
|
|
|
373
390
|
ractor_id: RedisQueuedLocks::Resource.get_ractor_id,
|
|
374
391
|
ttl:,
|
|
375
392
|
queue_ttl:,
|
|
393
|
+
lock_index_enabled: config['lock_index_enabled'],
|
|
394
|
+
lock_index_grace_period:,
|
|
376
395
|
timeout:,
|
|
377
396
|
timed:,
|
|
378
397
|
retry_count:,
|
|
@@ -407,11 +426,13 @@ class RedisQueuedLocks::Client
|
|
|
407
426
|
# rubocop:disable all
|
|
408
427
|
# @api public
|
|
409
428
|
# @since 1.16.0
|
|
429
|
+
# @version 1.21.0
|
|
410
430
|
def lock_series( # steep:ignore
|
|
411
431
|
*lock_names,
|
|
412
432
|
detailed_result: false,
|
|
413
433
|
ttl: config['default_lock_ttl'],
|
|
414
434
|
queue_ttl: config['default_queue_ttl'],
|
|
435
|
+
lock_index_grace_period: config['lock_index_grace_period'],
|
|
415
436
|
timeout: config['try_to_lock_timeout'],
|
|
416
437
|
timed: config['is_timed_by_default'],
|
|
417
438
|
retry_count: config['retry_count'],
|
|
@@ -449,6 +470,8 @@ class RedisQueuedLocks::Client
|
|
|
449
470
|
ractor_id: RedisQueuedLocks::Resource.get_ractor_id,
|
|
450
471
|
ttl:,
|
|
451
472
|
queue_ttl:,
|
|
473
|
+
lock_index_enabled: config['lock_index_enabled'],
|
|
474
|
+
lock_index_grace_period:,
|
|
452
475
|
timeout:,
|
|
453
476
|
timed:,
|
|
454
477
|
retry_count:,
|
|
@@ -483,11 +506,13 @@ class RedisQueuedLocks::Client
|
|
|
483
506
|
# rubocop:disable all
|
|
484
507
|
# @api public
|
|
485
508
|
# @since 1.16.0
|
|
509
|
+
# @version 1.21.0
|
|
486
510
|
def lock_series!( # steep:ignore
|
|
487
511
|
*lock_names,
|
|
488
512
|
detailed_result: false,
|
|
489
513
|
ttl: config['default_lock_ttl'],
|
|
490
514
|
queue_ttl: config['default_queue_ttl'],
|
|
515
|
+
lock_index_grace_period: config['lock_index_grace_period'],
|
|
491
516
|
timeout: config['try_to_lock_timeout'],
|
|
492
517
|
timed: config['is_timed_by_default'],
|
|
493
518
|
retry_count: config['retry_count'],
|
|
@@ -519,6 +544,7 @@ class RedisQueuedLocks::Client
|
|
|
519
544
|
detailed_result:,
|
|
520
545
|
ttl:,
|
|
521
546
|
queue_ttl:,
|
|
547
|
+
lock_index_grace_period:,
|
|
522
548
|
timeout:,
|
|
523
549
|
timed:,
|
|
524
550
|
retry_count:,
|
|
@@ -552,11 +578,12 @@ class RedisQueuedLocks::Client
|
|
|
552
578
|
#
|
|
553
579
|
# @api public
|
|
554
580
|
# @since 1.0.0
|
|
555
|
-
# @version 1.
|
|
581
|
+
# @version 1.21.0
|
|
556
582
|
def lock!(
|
|
557
583
|
lock_name,
|
|
558
584
|
ttl: config['default_lock_ttl'],
|
|
559
585
|
queue_ttl: config['default_queue_ttl'],
|
|
586
|
+
lock_index_grace_period: config['lock_index_grace_period'],
|
|
560
587
|
timeout: config['try_to_lock_timeout'],
|
|
561
588
|
timed: config['is_timed_by_default'],
|
|
562
589
|
retry_count: config['retry_count'],
|
|
@@ -587,6 +614,7 @@ class RedisQueuedLocks::Client
|
|
|
587
614
|
lock_name,
|
|
588
615
|
ttl:,
|
|
589
616
|
queue_ttl:,
|
|
617
|
+
lock_index_grace_period:,
|
|
590
618
|
timeout:,
|
|
591
619
|
timed:,
|
|
592
620
|
retry_count:,
|
|
@@ -645,7 +673,7 @@ class RedisQueuedLocks::Client
|
|
|
645
673
|
#
|
|
646
674
|
# @api public
|
|
647
675
|
# @since 1.0.0
|
|
648
|
-
# @version 1.
|
|
676
|
+
# @version 1.21.0
|
|
649
677
|
def unlock(
|
|
650
678
|
lock_name,
|
|
651
679
|
logger: config['logger'],
|
|
@@ -663,8 +691,10 @@ class RedisQueuedLocks::Client
|
|
|
663
691
|
RedisQueuedLocks::Acquirer::ReleaseLock.release_lock(
|
|
664
692
|
redis_client,
|
|
665
693
|
lock_name,
|
|
666
|
-
|
|
694
|
+
config['lock_index_enabled'],
|
|
667
695
|
logger,
|
|
696
|
+
instrumenter,
|
|
697
|
+
instrument,
|
|
668
698
|
log_sampling_enabled,
|
|
669
699
|
log_sampling_percent,
|
|
670
700
|
log_sampler,
|
|
@@ -721,7 +751,7 @@ class RedisQueuedLocks::Client
|
|
|
721
751
|
#
|
|
722
752
|
# @api public
|
|
723
753
|
# @since 1.18.0
|
|
724
|
-
# @version 1.
|
|
754
|
+
# @version 1.21.0
|
|
725
755
|
def unlock_read(
|
|
726
756
|
lock_name,
|
|
727
757
|
acquirer_id: nil,
|
|
@@ -742,8 +772,8 @@ class RedisQueuedLocks::Client
|
|
|
742
772
|
redis_client,
|
|
743
773
|
lock_name,
|
|
744
774
|
acquirer_id || current_acquirer_id(identity:),
|
|
745
|
-
instrumenter,
|
|
746
775
|
logger,
|
|
776
|
+
instrumenter,
|
|
747
777
|
instrument,
|
|
748
778
|
log_sampling_enabled,
|
|
749
779
|
log_sampling_percent,
|
|
@@ -881,19 +911,14 @@ class RedisQueuedLocks::Client
|
|
|
881
911
|
RedisQueuedLocks::Resource.possible_host_identifiers(identity)
|
|
882
912
|
end
|
|
883
913
|
|
|
884
|
-
#
|
|
885
|
-
#
|
|
886
|
-
#
|
|
887
|
-
# (2) set new ttl that is calculated as "current pttl + additional milliseconds"
|
|
888
|
-
# What can happen during these steps
|
|
889
|
-
# - lock is expired between commands or before the first command;
|
|
890
|
-
# - lock is expired before the second command;
|
|
891
|
-
# - lock is expired AND newly acquired by another process (so you will extend the
|
|
892
|
-
# totally new lock with fresh PTTL);
|
|
914
|
+
# The write lock TTL is extended atomically by one Lua script (`PTTL` + `PEXPIRE` with
|
|
915
|
+
# "current pttl + additional milliseconds") without the lock owner check: when your lock is
|
|
916
|
+
# expired and newly obtained by another acquirer, the lock of that acquirer is extended.
|
|
893
917
|
# Use it at your own risk and consider async nature when calling this method.
|
|
894
918
|
#
|
|
895
919
|
# @param lock_name [String]
|
|
896
|
-
# @param milliseconds [Integer]
|
|
920
|
+
# @param milliseconds [Integer]
|
|
921
|
+
# How many milliseconds should be added: a positive Integer.
|
|
897
922
|
# @option read_write_mode [Symbol]
|
|
898
923
|
# - `:write` (default) - extends the write lock (the method description above);
|
|
899
924
|
# - `:read` - extends the read lock of the current acquirer only (an expired read lock or
|
|
@@ -923,7 +948,7 @@ class RedisQueuedLocks::Client
|
|
|
923
948
|
#
|
|
924
949
|
# @api public
|
|
925
950
|
# @since 1.0.0
|
|
926
|
-
# @version 1.
|
|
951
|
+
# @version 1.21.0
|
|
927
952
|
def extend_lock_ttl(
|
|
928
953
|
lock_name,
|
|
929
954
|
milliseconds,
|
|
@@ -949,6 +974,7 @@ class RedisQueuedLocks::Client
|
|
|
949
974
|
read_write_mode,
|
|
950
975
|
all_read_locks,
|
|
951
976
|
current_acquirer_id(identity:),
|
|
977
|
+
config['lock_index_enabled'],
|
|
952
978
|
logger,
|
|
953
979
|
instrumenter,
|
|
954
980
|
instrument,
|
|
@@ -967,6 +993,7 @@ class RedisQueuedLocks::Client
|
|
|
967
993
|
# Returns:
|
|
968
994
|
# - :rel_time - (milliseconds) - time spent to release all locks and queues;
|
|
969
995
|
# - :rel_key_cnt - (integer) - the number of released redis keys (queus+locks);
|
|
996
|
+
# Locks are found via the keyspace SCAN or via the lock index (`config['lock_index_enabled']`).
|
|
970
997
|
#
|
|
971
998
|
# @option batch_size [Integer]
|
|
972
999
|
# @option logger [::Logger,#debug]
|
|
@@ -985,7 +1012,7 @@ class RedisQueuedLocks::Client
|
|
|
985
1012
|
#
|
|
986
1013
|
# @api public
|
|
987
1014
|
# @since 1.0.0
|
|
988
|
-
# @version 1.
|
|
1015
|
+
# @version 1.21.0
|
|
989
1016
|
def clear_locks(
|
|
990
1017
|
batch_size: config['lock_release_batch_size'],
|
|
991
1018
|
logger: config['logger'],
|
|
@@ -1003,6 +1030,7 @@ class RedisQueuedLocks::Client
|
|
|
1003
1030
|
RedisQueuedLocks::Acquirer::ReleaseAllLocks.release_all_locks(
|
|
1004
1031
|
redis_client,
|
|
1005
1032
|
batch_size,
|
|
1033
|
+
config['lock_index_enabled'],
|
|
1006
1034
|
logger,
|
|
1007
1035
|
instrumenter,
|
|
1008
1036
|
instrument,
|
|
@@ -1024,6 +1052,8 @@ class RedisQueuedLocks::Client
|
|
|
1024
1052
|
# current puma request thread is killed by Rack::Timeout and you need to cleanup all zombie RQL
|
|
1025
1053
|
# locks and lock reuqests obtained during the request processing).
|
|
1026
1054
|
#
|
|
1055
|
+
# Locks are found via the keyspace SCAN or via the lock index (`config['lock_index_enabled']`).
|
|
1056
|
+
#
|
|
1027
1057
|
# Identifiers can be extracted via:
|
|
1028
1058
|
# - `#current_host_id`
|
|
1029
1059
|
# - `#current_acquirer_id`
|
|
@@ -1071,11 +1101,12 @@ class RedisQueuedLocks::Client
|
|
|
1071
1101
|
#
|
|
1072
1102
|
# @api public
|
|
1073
1103
|
# @since 1.14.0
|
|
1104
|
+
# @version 1.21.0
|
|
1074
1105
|
def clear_locks_of(
|
|
1075
1106
|
host_id:,
|
|
1076
1107
|
acquirer_id:,
|
|
1077
1108
|
lock_scan_size: config['clear_locks_of__lock_scan_size'],
|
|
1078
|
-
queue_scan_size: config['clear_locks_of__queue_scan_size'],
|
|
1109
|
+
queue_scan_size: config['clear_locks_of__queue_scan_size'],
|
|
1079
1110
|
logger: config['logger'],
|
|
1080
1111
|
instrumenter: config['instrumenter'],
|
|
1081
1112
|
instrument: nil,
|
|
@@ -1094,6 +1125,7 @@ class RedisQueuedLocks::Client
|
|
|
1094
1125
|
redis_client,
|
|
1095
1126
|
lock_scan_size,
|
|
1096
1127
|
queue_scan_size,
|
|
1128
|
+
config['lock_index_enabled'],
|
|
1097
1129
|
logger,
|
|
1098
1130
|
instrumenter,
|
|
1099
1131
|
instrument,
|
|
@@ -1112,7 +1144,8 @@ class RedisQueuedLocks::Client
|
|
|
1112
1144
|
# Release all locks of the current acquirer/host and
|
|
1113
1145
|
# remove the current acquirer/host from all queues;
|
|
1114
1146
|
#
|
|
1115
|
-
# @option
|
|
1147
|
+
# @option lock_scan_size [Integer]
|
|
1148
|
+
# @option queue_scan_size [Integer]
|
|
1116
1149
|
# @option logger [::Logger,#debug]
|
|
1117
1150
|
# @option instrumenter [#notify] See `config['instrumenter']` docs for details.
|
|
1118
1151
|
# @option instrument [NilClass,Any]
|
|
@@ -1131,9 +1164,10 @@ class RedisQueuedLocks::Client
|
|
|
1131
1164
|
#
|
|
1132
1165
|
# @api public
|
|
1133
1166
|
# @since 1.14.0
|
|
1167
|
+
# @version 1.21.0
|
|
1134
1168
|
def clear_current_locks(
|
|
1135
1169
|
lock_scan_size: config['clear_locks_of__lock_scan_size'],
|
|
1136
|
-
queue_scan_size: config['clear_locks_of__queue_scan_size'],
|
|
1170
|
+
queue_scan_size: config['clear_locks_of__queue_scan_size'],
|
|
1137
1171
|
logger: config['logger'],
|
|
1138
1172
|
instrumenter: config['instrumenter'],
|
|
1139
1173
|
instrument: nil,
|
|
@@ -1183,10 +1217,16 @@ class RedisQueuedLocks::Client
|
|
|
1183
1217
|
# at the moment of Redis'es SCAN;
|
|
1184
1218
|
# @return [Set<String>,Set<Hash<Symbol,Any>>]
|
|
1185
1219
|
#
|
|
1220
|
+
# NOTE: locks are found via the keyspace SCAN or via the lock index (ZSCAN, the enabled
|
|
1221
|
+
# `config['lock_index_enabled']`: `scan_size` is the number of locks in one batch);
|
|
1222
|
+
#
|
|
1186
1223
|
# @api public
|
|
1187
1224
|
# @since 1.0.0
|
|
1225
|
+
# @version 1.21.0
|
|
1188
1226
|
def locks(scan_size: config['key_extraction_batch_size'], with_info: false)
|
|
1189
|
-
RedisQueuedLocks::Acquirer::Locks.locks(
|
|
1227
|
+
RedisQueuedLocks::Acquirer::Locks.locks(
|
|
1228
|
+
redis_client, scan_size:, with_info:, lock_index_enabled: config['lock_index_enabled']
|
|
1229
|
+
)
|
|
1190
1230
|
end
|
|
1191
1231
|
|
|
1192
1232
|
# Extracts lock keys with their info. See #locks(with_info: true) for details.
|
|
@@ -1196,8 +1236,9 @@ class RedisQueuedLocks::Client
|
|
|
1196
1236
|
#
|
|
1197
1237
|
# @api public
|
|
1198
1238
|
# @since 1.0.0
|
|
1199
|
-
|
|
1200
|
-
|
|
1239
|
+
# @version 1.21.0
|
|
1240
|
+
def locks_info(scan_size: config['key_extraction_batch_size'])
|
|
1241
|
+
locks(scan_size:, with_info: true) #: RedisQueuedLocks::Acquirer::Locks::locksInfo
|
|
1201
1242
|
end
|
|
1202
1243
|
|
|
1203
1244
|
# @option scan_size [Integer]
|
|
@@ -1214,10 +1255,16 @@ class RedisQueuedLocks::Client
|
|
|
1214
1255
|
# at the moment of Redis'es SCAN;
|
|
1215
1256
|
# @return [Set<String>,String<Hash<Symbol,Any>>]
|
|
1216
1257
|
#
|
|
1258
|
+
# NOTE: lock queues are found via the keyspace SCAN or via the lock index (ZSCAN, the enabled
|
|
1259
|
+
# `config['lock_index_enabled']`: `scan_size` is the number of locks in one batch);
|
|
1260
|
+
#
|
|
1217
1261
|
# @api public
|
|
1218
1262
|
# @since 1.0.0
|
|
1263
|
+
# @version 1.21.0
|
|
1219
1264
|
def queues(scan_size: config['key_extraction_batch_size'], with_info: false)
|
|
1220
|
-
RedisQueuedLocks::Acquirer::Queues.queues(
|
|
1265
|
+
RedisQueuedLocks::Acquirer::Queues.queues(
|
|
1266
|
+
redis_client, scan_size:, with_info:, lock_index_enabled: config['lock_index_enabled']
|
|
1267
|
+
)
|
|
1221
1268
|
end
|
|
1222
1269
|
|
|
1223
1270
|
# Extracts lock queues with their info. See #queues(with_info: true) for details.
|
|
@@ -1227,17 +1274,24 @@ class RedisQueuedLocks::Client
|
|
|
1227
1274
|
#
|
|
1228
1275
|
# @api public
|
|
1229
1276
|
# @since 1.0.0
|
|
1277
|
+
# @version 1.21.0
|
|
1230
1278
|
def queues_info(scan_size: config['key_extraction_batch_size'])
|
|
1231
|
-
queues(scan_size:, with_info: true)
|
|
1279
|
+
queues(scan_size:, with_info: true) #: RedisQueuedLocks::Acquirer::Queues::queuesInfo
|
|
1232
1280
|
end
|
|
1233
1281
|
|
|
1234
1282
|
# @option scan_size [Integer]
|
|
1235
1283
|
# @return [Set<String>]
|
|
1284
|
+
# - the disabled lock index: all the RQL keys (`rql:lock*`) found via the keyspace SCAN;
|
|
1285
|
+
# - the enabled lock index (`config['lock_index_enabled']`): the existing keys of the locks of
|
|
1286
|
+
# the lock index (ZSCAN, `scan_size` is the number of locks in one batch);
|
|
1236
1287
|
#
|
|
1237
1288
|
# @api public
|
|
1238
1289
|
# @since 1.0.0
|
|
1290
|
+
# @version 1.21.0
|
|
1239
1291
|
def keys(scan_size: config['key_extraction_batch_size'])
|
|
1240
|
-
RedisQueuedLocks::Acquirer::Keys.keys(
|
|
1292
|
+
RedisQueuedLocks::Acquirer::Keys.keys(
|
|
1293
|
+
redis_client, scan_size:, lock_index_enabled: config['lock_index_enabled']
|
|
1294
|
+
)
|
|
1241
1295
|
end
|
|
1242
1296
|
|
|
1243
1297
|
# @option dead_ttl [Integer]
|
|
@@ -1245,7 +1299,8 @@ class RedisQueuedLocks::Client
|
|
|
1245
1299
|
# considered as dead;
|
|
1246
1300
|
# - `config['dead_request_ttl']` is used by default;
|
|
1247
1301
|
# @option scan_size [Integer]
|
|
1248
|
-
# - the batch of scanned keys for Redis'es SCAN command
|
|
1302
|
+
# - the batch of scanned keys for Redis'es SCAN command (or the number of locks in one batch of
|
|
1303
|
+
# the lock index ZSCAN pass: the enabled `config['lock_index_enabled']`);
|
|
1249
1304
|
# - `config['lock_release_batch_size']` is used by default;
|
|
1250
1305
|
# @option logger [::Logger,#debug]
|
|
1251
1306
|
# @option instrumenter [#notify]
|
|
@@ -1263,7 +1318,7 @@ class RedisQueuedLocks::Client
|
|
|
1263
1318
|
#
|
|
1264
1319
|
# @api public
|
|
1265
1320
|
# @since 1.0.0
|
|
1266
|
-
# @version 1.
|
|
1321
|
+
# @version 1.21.0
|
|
1267
1322
|
def clear_dead_requests(
|
|
1268
1323
|
dead_ttl: config['dead_request_ttl'],
|
|
1269
1324
|
scan_size: config['lock_release_batch_size'],
|
|
@@ -1283,6 +1338,79 @@ class RedisQueuedLocks::Client
|
|
|
1283
1338
|
redis_client,
|
|
1284
1339
|
scan_size,
|
|
1285
1340
|
dead_ttl,
|
|
1341
|
+
config['lock_index_enabled'],
|
|
1342
|
+
logger,
|
|
1343
|
+
instrumenter,
|
|
1344
|
+
instrument,
|
|
1345
|
+
log_sampling_enabled,
|
|
1346
|
+
log_sampling_percent,
|
|
1347
|
+
log_sampler,
|
|
1348
|
+
log_sample_this,
|
|
1349
|
+
instr_sampling_enabled,
|
|
1350
|
+
instr_sampling_percent,
|
|
1351
|
+
instr_sampler,
|
|
1352
|
+
instr_sample_this
|
|
1353
|
+
)
|
|
1354
|
+
end
|
|
1355
|
+
|
|
1356
|
+
# Adds the lock keys without the lock index entry (keys of older RQL versions, keys created while
|
|
1357
|
+
# the lock index was disabled) to the lock index (`rql:index:locks`). Invoke it once after the lock
|
|
1358
|
+
# index is enabled (`config['lock_index_enabled']`) on all your processes: lock-iterating
|
|
1359
|
+
# operations (the swarm, `#locks`, `#queues`, `#keys`, `#clear_locks`, ...) find locks via
|
|
1360
|
+
# the lock index only.
|
|
1361
|
+
# - works regardless of `config['lock_index_enabled']` (the lock index is not used and not
|
|
1362
|
+
# maintained while it is disabled);
|
|
1363
|
+
# - one SCAN pass over the RQL keys;
|
|
1364
|
+
# - lock queues without TTL (older RQL versions) get `queue_ttl` as their TTL;
|
|
1365
|
+
# - idempotent: the lock index scores are never decreased, already indexed keys stay as is;
|
|
1366
|
+
#
|
|
1367
|
+
# @option scan_size [Integer]
|
|
1368
|
+
# - the batch of scanned keys for Redis'es SCAN command;
|
|
1369
|
+
# - `config['lock_release_batch_size']` is used by default;
|
|
1370
|
+
# @option queue_ttl [Integer]
|
|
1371
|
+
# - TTL of the lock queues without TTL (in seconds);
|
|
1372
|
+
# - `config['default_queue_ttl']` is used by default;
|
|
1373
|
+
# @option lock_index_grace_period [Integer]
|
|
1374
|
+
# - the lock index score margin over the key lifetime (in milliseconds);
|
|
1375
|
+
# - `config['lock_index_grace_period']` is used by default;
|
|
1376
|
+
# @option logger [::Logger,#debug]
|
|
1377
|
+
# @option instrumenter [#notify]
|
|
1378
|
+
# @option instrument [NilClass,Any]
|
|
1379
|
+
# @option log_sampling_enabled [Boolean]
|
|
1380
|
+
# @option log_sampling_percent [Integer]
|
|
1381
|
+
# @option log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
|
1382
|
+
# @option log_sample_this [Boolean]
|
|
1383
|
+
# @option instr_sampling_enabled [Boolean]
|
|
1384
|
+
# @option instr_sampling_percent [Integer]
|
|
1385
|
+
# @option instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
|
1386
|
+
# @option instr_sample_this [Boolean]
|
|
1387
|
+
# @return [Hash<Symbol,Boolean|Hash<Symbol,Integer>>]
|
|
1388
|
+
# Format: { ok: true, result: { idx_key_cnt: Integer } } (the number of indexed keys)
|
|
1389
|
+
#
|
|
1390
|
+
# @api public
|
|
1391
|
+
# @since 1.20.0
|
|
1392
|
+
# @version 1.21.0
|
|
1393
|
+
def reindex_locks(
|
|
1394
|
+
scan_size: config['lock_release_batch_size'],
|
|
1395
|
+
queue_ttl: config['default_queue_ttl'],
|
|
1396
|
+
lock_index_grace_period: config['lock_index_grace_period'],
|
|
1397
|
+
logger: config['logger'],
|
|
1398
|
+
instrumenter: config['instrumenter'],
|
|
1399
|
+
instrument: nil,
|
|
1400
|
+
log_sampling_enabled: config['log_sampling_enabled'],
|
|
1401
|
+
log_sampling_percent: config['log_sampling_percent'],
|
|
1402
|
+
log_sampler: config['log_sampler'],
|
|
1403
|
+
log_sample_this: false,
|
|
1404
|
+
instr_sampling_enabled: config['instr_sampling_enabled'],
|
|
1405
|
+
instr_sampling_percent: config['instr_sampling_percent'],
|
|
1406
|
+
instr_sampler: config['instr_sampler'],
|
|
1407
|
+
instr_sample_this: false
|
|
1408
|
+
)
|
|
1409
|
+
RedisQueuedLocks::Acquirer::ReindexLocks.reindex_locks(
|
|
1410
|
+
redis_client,
|
|
1411
|
+
scan_size,
|
|
1412
|
+
queue_ttl,
|
|
1413
|
+
lock_index_grace_period,
|
|
1286
1414
|
logger,
|
|
1287
1415
|
instrumenter,
|
|
1288
1416
|
instrument,
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
# @api private
|
|
4
4
|
# @since 1.13.0
|
|
5
|
-
# @version 1.15.1
|
|
6
5
|
# rubocop:disable Metrics/ClassLength
|
|
7
6
|
class RedisQueuedLocks::Config
|
|
8
7
|
require_relative 'config/dsl'
|
|
@@ -27,6 +26,8 @@ class RedisQueuedLocks::Config
|
|
|
27
26
|
setting('logger', RedisQueuedLocks::Logging::VoidLogger)
|
|
28
27
|
setting('log_lock_try', false)
|
|
29
28
|
setting('dead_request_ttl', 1 * 24 * 60 * 60 * 1000) # NOTE: 1 day in milliseconds)
|
|
29
|
+
setting('lock_index_enabled', false)
|
|
30
|
+
setting('lock_index_grace_period', 60_000) # NOTE: in milliseconds)
|
|
30
31
|
setting('is_timed_by_default', false)
|
|
31
32
|
setting('default_conflict_strategy', :wait_for_lock)
|
|
32
33
|
setting('default_access_strategy', :queued)
|
|
@@ -55,41 +56,43 @@ class RedisQueuedLocks::Config
|
|
|
55
56
|
setting('swarm.flush_zombies.redis_config.pool_config', {})
|
|
56
57
|
|
|
57
58
|
validate('swarm.auto_swarm') { |val| val == true || val == false }
|
|
58
|
-
validate('swarm.supervisor.liveness_probing_period') { |val| val.is_a?(Integer) }
|
|
59
|
+
validate('swarm.supervisor.liveness_probing_period') { |val| val.is_a?(Integer) && val > 0 }
|
|
59
60
|
|
|
60
61
|
validate('swarm.probe_hosts.enabled_for_swarm') { |val| val == true || val == false }
|
|
61
62
|
validate('swarm.probe_hosts.redis_config.sentinel') { |val| val == true || val == false }
|
|
62
63
|
validate('swarm.probe_hosts.redis_config.pooled') { |val| val == true || val == false }
|
|
63
64
|
validate('swarm.probe_hosts.redis_config.config') { |val| val.is_a?(Hash) }
|
|
64
65
|
validate('swarm.probe_hosts.redis_config.pool_config') { |val| val.is_a?(Hash) }
|
|
65
|
-
validate('swarm.probe_hosts.probe_period') { |val| val.is_a?(Integer) }
|
|
66
|
+
validate('swarm.probe_hosts.probe_period') { |val| val.is_a?(Integer) && val > 0 }
|
|
66
67
|
|
|
67
68
|
validate('swarm.flush_zombies.enabled_for_swarm') { |val| val == true || val == false }
|
|
68
69
|
validate('swarm.flush_zombies.redis_config.sentinel') { |val| val == true || val == false }
|
|
69
70
|
validate('swarm.flush_zombies.redis_config.pooled') { |val| val == true || val == false }
|
|
70
71
|
validate('swarm.flush_zombies.redis_config.config') { |val| val.is_a?(Hash) }
|
|
71
72
|
validate('swarm.flush_zombies.redis_config.pool_config') { |val| val.is_a?(Hash) }
|
|
72
|
-
validate('swarm.flush_zombies.zombie_ttl') { |val| val.is_a?(Integer) }
|
|
73
|
-
validate('swarm.flush_zombies.zombie_lock_scan_size') { |val| val.is_a?(Integer) }
|
|
74
|
-
validate('swarm.flush_zombies.zombie_queue_scan_size') { |val| val.is_a?(Integer) }
|
|
75
|
-
validate('swarm.flush_zombies.zombie_flush_period') { |val| val.is_a?(Integer) }
|
|
73
|
+
validate('swarm.flush_zombies.zombie_ttl') { |val| val.is_a?(Integer) && val > 0 }
|
|
74
|
+
validate('swarm.flush_zombies.zombie_lock_scan_size') { |val| val.is_a?(Integer) && val > 0 }
|
|
75
|
+
validate('swarm.flush_zombies.zombie_queue_scan_size') { |val| val.is_a?(Integer) && val > 0 }
|
|
76
|
+
validate('swarm.flush_zombies.zombie_flush_period') { |val| val.is_a?(Integer) && val > 0 }
|
|
76
77
|
|
|
77
78
|
validate('retry_count') { |val| val == nil || (val.is_a?(Integer) && val >= 0) }
|
|
78
79
|
validate('retry_delay') { |val| val.is_a?(Integer) && val >= 0 }
|
|
79
80
|
validate('retry_jitter') { |val| val.is_a?(Integer) && val >= 0 }
|
|
80
81
|
validate('try_to_lock_timeout') { |val| val == nil || (val.is_a?(Integer) && val >= 0) }
|
|
81
|
-
validate('default_lock_ttl') { |val| val.is_a?(Integer) }
|
|
82
|
-
validate('default_queue_ttl') { |val| val.is_a?(Integer) }
|
|
82
|
+
validate('default_lock_ttl') { |val| val.is_a?(Integer) && val > 0 }
|
|
83
|
+
validate('default_queue_ttl') { |val| val.is_a?(Integer) && val > 0 }
|
|
83
84
|
validate('detailed_acq_timeout_error') { |val| val == true || val == false }
|
|
84
|
-
validate('lock_release_batch_size') { |val| val.is_a?(Integer) }
|
|
85
|
-
validate('clear_locks_of__lock_scan_size') { |val| val.is_a?(Integer) }
|
|
86
|
-
validate('clear_locks_of__queue_scan_size') { |val| val.is_a?(Integer) }
|
|
87
|
-
validate('key_extraction_batch_size') { |val| val.is_a?(Integer) }
|
|
85
|
+
validate('lock_release_batch_size') { |val| val.is_a?(Integer) && val > 0 }
|
|
86
|
+
validate('clear_locks_of__lock_scan_size') { |val| val.is_a?(Integer) && val > 0 }
|
|
87
|
+
validate('clear_locks_of__queue_scan_size') { |val| val.is_a?(Integer) && val > 0 }
|
|
88
|
+
validate('key_extraction_batch_size') { |val| val.is_a?(Integer) && val > 0 }
|
|
88
89
|
validate('instrumenter') { |val| RedisQueuedLocks::Instrument.valid_interface?(val) }
|
|
89
90
|
validate('uniq_identifier') { |val| val.is_a?(Proc) }
|
|
90
91
|
validate('logger') { |val| RedisQueuedLocks::Logging.valid_interface?(val) }
|
|
91
92
|
validate('log_lock_try') { |val| val == true || val == false }
|
|
92
93
|
validate('dead_request_ttl') { |val| val.is_a?(Integer) && val > 0 }
|
|
94
|
+
validate('lock_index_enabled') { |val| val == true || val == false }
|
|
95
|
+
validate('lock_index_grace_period') { |val| val.is_a?(Integer) && val >= 0 }
|
|
93
96
|
validate('is_timed_by_default') { |val| val == true || val == false }
|
|
94
97
|
validate('log_sampler') { |val| RedisQueuedLocks::Logging.valid_sampler?(val) }
|
|
95
98
|
validate('log_sampling_enabled') { |val| val == true || val == false }
|
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
# the one-line definition style (like "Error = Class.new(::StandardError)")
|
|
5
5
|
# is not used cuz that style can not be correctly defined via RBS types: we can not
|
|
6
6
|
# identify the superclass of our class for a constant;
|
|
7
|
+
# NOTE: (error hierarchy) each error inherits from the global base error of its branch:
|
|
8
|
+
# - `Error` (`::StandardError`) - the main hierarchy;
|
|
9
|
+
# - `ArgumentError` (`::ArgumentError`) - invalid arguments (the Ruby core branch that can not be
|
|
10
|
+
# a part of the main hierarchy);
|
|
11
|
+
# - `Exception` (`::Exception`) - super exceptional cases only: each error of this branch
|
|
12
|
+
# describes why it is not a `StandardError`;
|
|
7
13
|
module RedisQueuedLocks
|
|
8
14
|
# @api public
|
|
9
15
|
# @since 1.0.0
|
|
@@ -13,13 +19,29 @@ module RedisQueuedLocks
|
|
|
13
19
|
# @since 1.0.0
|
|
14
20
|
class ArgumentError < ::ArgumentError; end
|
|
15
21
|
|
|
22
|
+
# The base of the errors that should not be rescued by the code they interrupt
|
|
23
|
+
# (`rescue => e`, `rescue StandardError`, `rescue nil`): like `Timeout::ExitException`,
|
|
24
|
+
# they are rescued only by `rescue Exception` (and by the library itself).
|
|
25
|
+
# NOTE: inside `module RedisQueuedLocks` a bare `Exception` refers to this class;
|
|
26
|
+
#
|
|
27
|
+
# @api private
|
|
28
|
+
# @since 1.21.0
|
|
29
|
+
class Exception < ::Exception; end # rubocop:disable Lint/InheritException
|
|
30
|
+
|
|
16
31
|
# @api public
|
|
17
32
|
# @since 1.0.0
|
|
18
33
|
class LockAlreadyObtainedError < Error; end
|
|
19
34
|
|
|
35
|
+
# Interrupts the lock acquirement after the `timeout` (`Timeout.timeout`); rescued by
|
|
36
|
+
# `WithAcqTimeout` (=> `LockAcquirementTimeoutError` / `:timeout_reached`).
|
|
37
|
+
# NOTE: (why `Exception`) the acquirement calls the logger and the instrumenter: a `StandardError`
|
|
38
|
+
# that interrupts them is swallowed by `rescue nil` of the log/instrumentation events, and the
|
|
39
|
+
# acquirement continues without the timeout (with `retry_count: nil` - without any limit);
|
|
40
|
+
#
|
|
20
41
|
# @api private
|
|
21
42
|
# @since 1.11.0
|
|
22
|
-
|
|
43
|
+
# @version 1.21.0
|
|
44
|
+
class LockAcquirementIntermediateTimeoutError < Exception; end
|
|
23
45
|
|
|
24
46
|
# @api public
|
|
25
47
|
# @since 1.0.0
|
|
@@ -29,11 +51,19 @@ module RedisQueuedLocks
|
|
|
29
51
|
# @since 1.0.0
|
|
30
52
|
class LockAcquirementRetryLimitError < Error; end
|
|
31
53
|
|
|
54
|
+
# Interrupts the `timed: true` block after the lock ttl (`Timeout.timeout`); rescued by
|
|
55
|
+
# `YieldExpire` (=> `TimedLockTimeoutError`).
|
|
56
|
+
# NOTE: (why `Exception`) a `StandardError` is swallowed by `rescue => e` / `rescue nil` of
|
|
57
|
+
# the user block: the block continues after the lock ttl (without the mutual exclusion:
|
|
58
|
+
# another acquirer can obtain the expired lock, and the write lock release after the block
|
|
59
|
+
# deletes its lock);
|
|
60
|
+
#
|
|
32
61
|
# @api private
|
|
33
62
|
# @since 1.12.0
|
|
34
|
-
|
|
63
|
+
# @version 1.21.0
|
|
64
|
+
class TimedLockIntermediateTimeoutError < Exception; end
|
|
35
65
|
|
|
36
|
-
# @api
|
|
66
|
+
# @api public
|
|
37
67
|
# @since 1.0.0
|
|
38
68
|
class TimedLockTimeoutError < Error; end
|
|
39
69
|
|
|
@@ -57,7 +87,7 @@ module RedisQueuedLocks
|
|
|
57
87
|
# @since 1.13.0
|
|
58
88
|
class ConfigNotFoundError < ConfigError; end
|
|
59
89
|
|
|
60
|
-
# @api
|
|
90
|
+
# @api public
|
|
61
91
|
# @since 1.13.0
|
|
62
92
|
class ConfigValidationError < ConfigError; end
|
|
63
93
|
end
|