redis_queued_locks 1.5.0 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -1
- data/README.md +234 -58
- data/lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +36 -0
- data/lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue.rb +39 -0
- data/lib/redis_queued_locks/acquier/acquire_lock/instr_visitor.rb +151 -0
- data/lib/redis_queued_locks/acquier/acquire_lock/log_visitor.rb +192 -0
- data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock/log_visitor.rb +485 -0
- data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock.rb +76 -197
- data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire/log_visitor.rb +68 -0
- data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire.rb +17 -21
- data/lib/redis_queued_locks/acquier/acquire_lock.rb +128 -123
- data/lib/redis_queued_locks/acquier/clear_dead_requests.rb +8 -1
- data/lib/redis_queued_locks/acquier/extend_lock_ttl.rb +12 -2
- data/lib/redis_queued_locks/acquier/release_all_locks.rb +44 -8
- data/lib/redis_queued_locks/acquier/release_lock.rb +46 -14
- data/lib/redis_queued_locks/client.rb +128 -31
- data/lib/redis_queued_locks/instrument/sampler.rb +27 -0
- data/lib/redis_queued_locks/instrument.rb +47 -0
- data/lib/redis_queued_locks/logging/sampler.rb +10 -3
- data/lib/redis_queued_locks/logging.rb +1 -0
- data/lib/redis_queued_locks/utilities.rb +0 -1
- data/lib/redis_queued_locks/version.rb +2 -2
- data/lib/redis_queued_locks/watcher.rb +1 -0
- data/redis_queued_locks.gemspec +23 -3
- metadata +15 -6
@@ -23,9 +23,13 @@ class RedisQueuedLocks::Client
|
|
23
23
|
setting :dead_request_ttl, (1 * 24 * 60 * 60 * 1000) # NOTE: 1 day in milliseconds
|
24
24
|
setting :is_timed_by_default, false
|
25
25
|
setting :default_conflict_strategy, :wait_for_lock
|
26
|
+
setting :default_access_strategy, :queued
|
26
27
|
setting :log_sampling_enabled, false
|
27
28
|
setting :log_sampling_percent, 15
|
28
29
|
setting :log_sampler, RedisQueuedLocks::Logging::Sampler
|
30
|
+
setting :instr_sampling_enabled, false
|
31
|
+
setting :instr_sampling_percent, 15
|
32
|
+
setting :instr_sampler, RedisQueuedLocks::Instrument::Sampler
|
29
33
|
|
30
34
|
validate('retry_count') { |val| val == nil || (val.is_a?(::Integer) && val >= 0) }
|
31
35
|
validate('retry_delay') { |val| val.is_a?(::Integer) && val >= 0 }
|
@@ -43,6 +47,9 @@ class RedisQueuedLocks::Client
|
|
43
47
|
validate('log_sampler') { |val| RedisQueuedLocks::Logging.valid_sampler?(val) }
|
44
48
|
validate('log_sampling_enabled', :boolean)
|
45
49
|
validate('log_sampling_percent') { |val| val.is_a?(::Integer) && val >= 0 && val <= 100 }
|
50
|
+
validate('instr_sampling_enabled', :boolean)
|
51
|
+
validate('instr_sampling_percent') { |val| val.is_a?(::Integer) && val >= 0 && val <= 100 }
|
52
|
+
validate('instr_sampler') { |val| RedisQueuedLocks::Instrument.valid_sampler?(val) }
|
46
53
|
validate('default_conflict_strategy') do |val|
|
47
54
|
# rubocop:disable Layout/MultilineOperationIndentation
|
48
55
|
val == :work_through ||
|
@@ -51,6 +58,12 @@ class RedisQueuedLocks::Client
|
|
51
58
|
val == :dead_locking
|
52
59
|
# rubocop:enable Layout/MultilineOperationIndentation
|
53
60
|
end
|
61
|
+
validate('default_access_strategy') do |val|
|
62
|
+
# rubocop:disable Layout/MultilineOperationIndentation
|
63
|
+
val == :queued ||
|
64
|
+
val == :random
|
65
|
+
# rubocop:enable Layout/MultilineOperationIndentation
|
66
|
+
end
|
54
67
|
end
|
55
68
|
|
56
69
|
# @return [RedisClient]
|
@@ -98,8 +111,6 @@ class RedisQueuedLocks::Client
|
|
98
111
|
# A time-interval between the each retry (in milliseconds).
|
99
112
|
# @option retry_jitter [Integer]
|
100
113
|
# Time-shift range for retry-delay (in milliseconds).
|
101
|
-
# @option instrumenter [#notify]
|
102
|
-
# See RedisQueuedLocks::Instrument::ActiveSupport for example.
|
103
114
|
# @option raise_errors [Boolean]
|
104
115
|
# Raise errors on library-related limits such as timeout or failed lock obtain.
|
105
116
|
# @option identity [String]
|
@@ -122,6 +133,16 @@ class RedisQueuedLocks::Client
|
|
122
133
|
# - `:wait_for_lock` - (default) - work in classic way
|
123
134
|
# (with timeouts, retry delays, retry limits, etc - in classic way :));
|
124
135
|
# - `:dead_locking` - fail with deadlock exception;
|
136
|
+
# @option access_strategy [Symbol]
|
137
|
+
# - The way in which the lock will be obtained;
|
138
|
+
# - By default it uses `:queued` strategy;
|
139
|
+
# - Supports following strategies:
|
140
|
+
# - `:queued` (FIFO): the classic queued behavior (default), your lock will be
|
141
|
+
# obitaned if you are first in queue and the required lock is free;
|
142
|
+
# - `:random` (RANDOM): obtain a lock without checking the positions in the queue
|
143
|
+
# (but with checking the limist, retries, timeouts and so on). if lock is
|
144
|
+
# free to obtain - it will be obtained;
|
145
|
+
# - pre-configured in `config[:default_access_strategy]`;
|
125
146
|
# @option meta [NilClass,Hash<String|Symbol,Any>]
|
126
147
|
# - A custom metadata wich will be passed to the lock data in addition to the existing data;
|
127
148
|
# - Metadata can not contain reserved lock data keys;
|
@@ -133,6 +154,12 @@ class RedisQueuedLocks::Client
|
|
133
154
|
# - should be logged the each try of lock acquiring (a lot of logs can
|
134
155
|
# be generated depending on your retry configurations);
|
135
156
|
# - see `config[:log_lock_try]`;
|
157
|
+
# @option instrumenter [#notify]
|
158
|
+
# - Custom instrumenter that will be invoked via #notify method with `event` and `payload` data;
|
159
|
+
# - See RedisQueuedLocks::Instrument::ActiveSupport for examples and implementation details;
|
160
|
+
# - See [Instrumentation](#instrumentation) section of docs;
|
161
|
+
# - pre-configured in `config[:isntrumenter]` with void notifier
|
162
|
+
# (`RedisQueuedLocks::Instrumenter::VoidNotifier`);
|
136
163
|
# @option instrument [NilClass,Any]
|
137
164
|
# - Custom instrumentation data wich will be passed to the instrumenter's payload
|
138
165
|
# with :instrument key;
|
@@ -153,6 +180,24 @@ class RedisQueuedLocks::Client
|
|
153
180
|
# - you can provide your own log sampler with bettter algorithm that should realize
|
154
181
|
# `sampling_happened?(percent) => boolean` interface
|
155
182
|
# (see `RedisQueuedLocks::Logging::Sampler` for example);
|
183
|
+
# @option instr_sampling_enabled [Boolean]
|
184
|
+
# - enables <instrumentaion sampling>: only the configured percent
|
185
|
+
# of RQL cases will be instrumented;
|
186
|
+
# - disabled by default;
|
187
|
+
# - works in tandem with <config.instr_sampling_percent and <log.instr_sampler>;
|
188
|
+
# @option instr_sampling_percent [Integer]
|
189
|
+
# - the percent of cases that should be instrumented;
|
190
|
+
# - take an effect when <config.instr_sampling_enalbed> is true;
|
191
|
+
# - works in tandem with <config.instr_sampling_enabled> and <config.instr_sampler> configs;
|
192
|
+
# @option instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
193
|
+
# - percent-based log sampler that decides should be RQL case instrumented or not;
|
194
|
+
# - works in tandem with <config.instr_sampling_enabled> and
|
195
|
+
# <config.instr_sampling_percent> configs;
|
196
|
+
# - based on the ultra simple percent-based (weight-based) algorithm that uses SecureRandom.rand
|
197
|
+
# method so the algorithm error is ~(0%..13%);
|
198
|
+
# - you can provide your own log sampler with bettter algorithm that should realize
|
199
|
+
# `sampling_happened?(percent) => boolean` interface
|
200
|
+
# (see `RedisQueuedLocks::Instrument::Sampler` for example);
|
156
201
|
# @param block [Block]
|
157
202
|
# A block of code that should be executed after the successfully acquired lock.
|
158
203
|
# @return [RedisQueuedLocks::Data,Hash<Symbol,Any>,yield]
|
@@ -161,7 +206,7 @@ class RedisQueuedLocks::Client
|
|
161
206
|
#
|
162
207
|
# @api public
|
163
208
|
# @since 1.0.0
|
164
|
-
# @version 1.
|
209
|
+
# @version 1.7.0
|
165
210
|
# rubocop:disable Metrics/MethodLength
|
166
211
|
def lock(
|
167
212
|
lock_name,
|
@@ -175,14 +220,19 @@ class RedisQueuedLocks::Client
|
|
175
220
|
raise_errors: false,
|
176
221
|
fail_fast: false,
|
177
222
|
conflict_strategy: config[:default_conflict_strategy],
|
223
|
+
access_strategy: config[:default_access_strategy],
|
178
224
|
identity: uniq_identity,
|
179
225
|
meta: nil,
|
180
226
|
logger: config[:logger],
|
181
227
|
log_lock_try: config[:log_lock_try],
|
228
|
+
instrumenter: config[:instrumenter],
|
182
229
|
instrument: nil,
|
183
230
|
log_sampling_enabled: config[:log_sampling_enabled],
|
184
231
|
log_sampling_percent: config[:log_sampling_percent],
|
185
232
|
log_sampler: config[:log_sampler],
|
233
|
+
instr_sampling_enabled: config[:instr_sampling_enabled],
|
234
|
+
instr_sampling_percent: config[:instr_sampling_percent],
|
235
|
+
instr_sampler: config[:instr_sampler],
|
186
236
|
&block
|
187
237
|
)
|
188
238
|
RedisQueuedLocks::Acquier::AcquireLock.acquire_lock(
|
@@ -200,10 +250,11 @@ class RedisQueuedLocks::Client
|
|
200
250
|
retry_delay:,
|
201
251
|
retry_jitter:,
|
202
252
|
raise_errors:,
|
203
|
-
instrumenter
|
253
|
+
instrumenter:,
|
204
254
|
identity:,
|
205
255
|
fail_fast:,
|
206
256
|
conflict_strategy:,
|
257
|
+
access_strategy:,
|
207
258
|
meta:,
|
208
259
|
logger:,
|
209
260
|
log_lock_try:,
|
@@ -211,6 +262,9 @@ class RedisQueuedLocks::Client
|
|
211
262
|
log_sampling_enabled:,
|
212
263
|
log_sampling_percent:,
|
213
264
|
log_sampler:,
|
265
|
+
instr_sampling_enabled:,
|
266
|
+
instr_sampling_percent:,
|
267
|
+
instr_sampler:,
|
214
268
|
&block
|
215
269
|
)
|
216
270
|
end
|
@@ -220,7 +274,8 @@ class RedisQueuedLocks::Client
|
|
220
274
|
#
|
221
275
|
# @api public
|
222
276
|
# @since 1.0.0
|
223
|
-
# @version 1.
|
277
|
+
# @version 1.7.0
|
278
|
+
# rubocop:disable Metrics/MethodLength
|
224
279
|
def lock!(
|
225
280
|
lock_name,
|
226
281
|
ttl: config[:default_lock_ttl],
|
@@ -232,7 +287,9 @@ class RedisQueuedLocks::Client
|
|
232
287
|
retry_jitter: config[:retry_jitter],
|
233
288
|
fail_fast: false,
|
234
289
|
conflict_strategy: config[:default_conflict_strategy],
|
290
|
+
access_strategy: config[:default_access_strategy],
|
235
291
|
identity: uniq_identity,
|
292
|
+
instrumenter: config[:instrumenter],
|
236
293
|
meta: nil,
|
237
294
|
logger: config[:logger],
|
238
295
|
log_lock_try: config[:log_lock_try],
|
@@ -240,6 +297,9 @@ class RedisQueuedLocks::Client
|
|
240
297
|
log_sampling_enabled: config[:log_sampling_enabled],
|
241
298
|
log_sampling_percent: config[:log_sampling_percent],
|
242
299
|
log_sampler: config[:log_sampler],
|
300
|
+
instr_sampling_enabled: config[:instr_sampling_enabled],
|
301
|
+
instr_sampling_percent: config[:instr_sampling_percent],
|
302
|
+
instr_sampler: config[:instr_sampler],
|
243
303
|
&block
|
244
304
|
)
|
245
305
|
lock(
|
@@ -258,13 +318,19 @@ class RedisQueuedLocks::Client
|
|
258
318
|
log_lock_try:,
|
259
319
|
meta:,
|
260
320
|
instrument:,
|
321
|
+
instrumenter:,
|
261
322
|
conflict_strategy:,
|
323
|
+
access_strategy:,
|
262
324
|
log_sampling_enabled:,
|
263
325
|
log_sampling_percent:,
|
264
326
|
log_sampler:,
|
327
|
+
instr_sampling_enabled:,
|
328
|
+
instr_sampling_percent:,
|
329
|
+
instr_sampler:,
|
265
330
|
&block
|
266
331
|
)
|
267
332
|
end
|
333
|
+
# rubocop:enable Metrics/MethodLength
|
268
334
|
|
269
335
|
# @param lock_name [String] The lock name that should be released.
|
270
336
|
# @option logger [::Logger,#debug]
|
@@ -273,6 +339,9 @@ class RedisQueuedLocks::Client
|
|
273
339
|
# @option log_sampling_enabled [Boolean]
|
274
340
|
# @option log_sampling_percent [Integer]
|
275
341
|
# @option log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
342
|
+
# @option instr_sampling_enabled [Boolean]
|
343
|
+
# @option instr_sampling_percent [Integer]
|
344
|
+
# @option instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
276
345
|
# @return [RedisQueuedLocks::Data, Hash<Symbol,Any>]
|
277
346
|
# Format: {
|
278
347
|
# ok: true/false,
|
@@ -287,7 +356,7 @@ class RedisQueuedLocks::Client
|
|
287
356
|
#
|
288
357
|
# @api public
|
289
358
|
# @since 1.0.0
|
290
|
-
# @version 1.
|
359
|
+
# @version 1.6.0
|
291
360
|
def unlock(
|
292
361
|
lock_name,
|
293
362
|
logger: config[:logger],
|
@@ -295,16 +364,22 @@ class RedisQueuedLocks::Client
|
|
295
364
|
instrument: nil,
|
296
365
|
log_sampling_enabled: config[:log_sampling_enabled],
|
297
366
|
log_sampling_percent: config[:log_sampling_percent],
|
298
|
-
log_sampler: config[:log_sampler]
|
367
|
+
log_sampler: config[:log_sampler],
|
368
|
+
instr_sampling_enabled: config[:instr_sampling_enabled],
|
369
|
+
instr_sampling_percent: config[:instr_sampling_percent],
|
370
|
+
instr_sampler: config[:instr_sampler]
|
299
371
|
)
|
300
372
|
RedisQueuedLocks::Acquier::ReleaseLock.release_lock(
|
301
373
|
redis_client,
|
302
374
|
lock_name,
|
303
|
-
|
304
|
-
|
375
|
+
instrumenter,
|
376
|
+
logger,
|
305
377
|
log_sampling_enabled,
|
306
378
|
log_sampling_percent,
|
307
|
-
log_sampler
|
379
|
+
log_sampler,
|
380
|
+
instr_sampling_enabled,
|
381
|
+
instr_sampling_percent,
|
382
|
+
instr_sampler
|
308
383
|
)
|
309
384
|
end
|
310
385
|
|
@@ -358,43 +433,47 @@ class RedisQueuedLocks::Client
|
|
358
433
|
# @param lock_name [String]
|
359
434
|
# @param milliseconds [Integer] How many milliseconds should be added.
|
360
435
|
# @option logger [::Logger,#debug]
|
436
|
+
# @option instrumenter [#notify] See `config[:instrumenter]` docs for details.
|
437
|
+
# @option instrument [NilClass,Any]
|
361
438
|
# @option log_sampling_enabled [Boolean]
|
362
|
-
# - The percent of cases that should be logged;
|
363
|
-
# - Sampling algorithm is super simple and works via SecureRandom.rand method
|
364
|
-
# on the base of "weight" algorithm;
|
365
|
-
# - You can provide your own sampler via config[:log_sampler] config and :sampler option
|
366
|
-
# (see `RedisQueuedLocks::Logging::Sampler` for examples);
|
367
|
-
# - The spread of guaranteed percent is approximately +13% (rand method spread);
|
368
|
-
# - Take an effect when <log_sampling_enabled> parameter has <true> value
|
369
|
-
# (when log sampling is enabled);
|
370
439
|
# @option log_sampling_percent [Integer]
|
371
|
-
# - The percent of cases that should be logged;
|
372
|
-
# - Take an effect when <log_sampling_enabled> parameter has <true> value
|
373
|
-
# (when log sampling is enabled);
|
374
440
|
# @option log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
441
|
+
# @option instr_sampling_enabled [Boolean]
|
442
|
+
# @option instr_sampling_percent [Integer]
|
443
|
+
# @option instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
375
444
|
# @return [Hash<Symbol,Boolean|Symbol>]
|
376
445
|
# - { ok: true, result: :ttl_extended }
|
377
446
|
# - { ok: false, result: :async_expire_or_no_lock }
|
378
447
|
#
|
379
448
|
# @api public
|
380
449
|
# @since 1.0.0
|
381
|
-
# @version 1.
|
450
|
+
# @version 1.6.0
|
382
451
|
def extend_lock_ttl(
|
383
452
|
lock_name,
|
384
453
|
milliseconds,
|
385
454
|
logger: config[:logger],
|
455
|
+
instrumenter: config[:instrumenter],
|
456
|
+
instrument: nil,
|
386
457
|
log_sampling_enabled: config[:log_sampling_enabled],
|
387
458
|
log_sampling_percent: config[:log_sampling_percent],
|
388
|
-
log_sampler: config[:log_sampler]
|
459
|
+
log_sampler: config[:log_sampler],
|
460
|
+
instr_sampling_enabled: config[:instr_sampling_enabled],
|
461
|
+
instr_sampling_percent: config[:instr_sampling_percent],
|
462
|
+
instr_sampler: config[:instr_sampler]
|
389
463
|
)
|
390
464
|
RedisQueuedLocks::Acquier::ExtendLockTTL.extend_lock_ttl(
|
391
465
|
redis_client,
|
392
466
|
lock_name,
|
393
467
|
milliseconds,
|
394
468
|
logger,
|
469
|
+
instrumenter,
|
470
|
+
instrument,
|
395
471
|
log_sampling_enabled,
|
396
472
|
log_sampling_percent,
|
397
|
-
log_sampler
|
473
|
+
log_sampler,
|
474
|
+
instr_sampling_enabled,
|
475
|
+
instr_sampling_percent,
|
476
|
+
instr_sampler
|
398
477
|
)
|
399
478
|
end
|
400
479
|
|
@@ -405,17 +484,20 @@ class RedisQueuedLocks::Client
|
|
405
484
|
#
|
406
485
|
# @option batch_size [Integer]
|
407
486
|
# @option logger [::Logger,#debug]
|
408
|
-
# @option instrumenter [#notify]
|
487
|
+
# @option instrumenter [#notify] See `config[:instrumenter]` docs for details.
|
409
488
|
# @option instrument [NilClass,Any]
|
410
489
|
# @option log_sampling_enabled [Boolean]
|
411
490
|
# @option log_sampling_percent [Integer]
|
412
491
|
# @option log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
492
|
+
# @option instr_sampling_enabled [Boolean]
|
493
|
+
# @option instr_sampling_percent [Integer]
|
494
|
+
# @option instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
413
495
|
# @return [RedisQueuedLocks::Data,Hash<Symbol,Boolean|Hash<Symbol,Numeric>>]
|
414
496
|
# Example: { ok: true, result { rel_key_cnt: 100, rel_time: 0.01 } }
|
415
497
|
#
|
416
498
|
# @api public
|
417
499
|
# @since 1.0.0
|
418
|
-
# @version 1.
|
500
|
+
# @version 1.6.0
|
419
501
|
def clear_locks(
|
420
502
|
batch_size: config[:lock_release_batch_size],
|
421
503
|
logger: config[:logger],
|
@@ -423,7 +505,10 @@ class RedisQueuedLocks::Client
|
|
423
505
|
instrument: nil,
|
424
506
|
log_sampling_enabled: config[:log_sampling_enabled],
|
425
507
|
log_sampling_percent: config[:log_sampling_percent],
|
426
|
-
log_sampler: config[:log_sampler]
|
508
|
+
log_sampler: config[:log_sampler],
|
509
|
+
instr_sampling_enabled: config[:instr_sampling_enabled],
|
510
|
+
instr_sampling_percent: config[:instr_sampling_percent],
|
511
|
+
instr_sampler: config[:instr_sampler]
|
427
512
|
)
|
428
513
|
RedisQueuedLocks::Acquier::ReleaseAllLocks.release_all_locks(
|
429
514
|
redis_client,
|
@@ -433,7 +518,10 @@ class RedisQueuedLocks::Client
|
|
433
518
|
instrument,
|
434
519
|
log_sampling_enabled,
|
435
520
|
log_sampling_percent,
|
436
|
-
log_sampler
|
521
|
+
log_sampler,
|
522
|
+
instr_sampling_enabled,
|
523
|
+
instr_sampling_percent,
|
524
|
+
instr_sampler
|
437
525
|
)
|
438
526
|
end
|
439
527
|
|
@@ -524,12 +612,15 @@ class RedisQueuedLocks::Client
|
|
524
612
|
# @option log_sampling_enabled [Boolean]
|
525
613
|
# @option log_sampling_percent [Integer]
|
526
614
|
# @option log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
615
|
+
# @option instr_sampling_enabled [Boolean]
|
616
|
+
# @option instr_sampling_percent [Integer]
|
617
|
+
# @option instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
527
618
|
# @return [Hash<Symbol,Boolean|Hash<Symbol,Set<String>>>]
|
528
619
|
# Format: { ok: true, result: { processed_queus: Set<String> } }
|
529
620
|
#
|
530
621
|
# @api public
|
531
622
|
# @since 1.0.0
|
532
|
-
# @version 1.
|
623
|
+
# @version 1.6.0
|
533
624
|
def clear_dead_requests(
|
534
625
|
dead_ttl: config[:dead_request_ttl],
|
535
626
|
scan_size: config[:lock_release_batch_size],
|
@@ -538,7 +629,10 @@ class RedisQueuedLocks::Client
|
|
538
629
|
instrument: nil,
|
539
630
|
log_sampling_enabled: config[:log_sampling_enabled],
|
540
631
|
log_sampling_percent: config[:log_sampling_percent],
|
541
|
-
log_sampler: config[:log_sampler]
|
632
|
+
log_sampler: config[:log_sampler],
|
633
|
+
instr_sampling_enabled: config[:instr_sampling_enabled],
|
634
|
+
instr_sampling_percent: config[:instr_sampling_percent],
|
635
|
+
instr_sampler: config[:instr_sampler]
|
542
636
|
)
|
543
637
|
RedisQueuedLocks::Acquier::ClearDeadRequests.clear_dead_requests(
|
544
638
|
redis_client,
|
@@ -549,7 +643,10 @@ class RedisQueuedLocks::Client
|
|
549
643
|
instrument,
|
550
644
|
log_sampling_enabled,
|
551
645
|
log_sampling_percent,
|
552
|
-
log_sampler
|
646
|
+
log_sampler,
|
647
|
+
instr_sampling_enabled,
|
648
|
+
instr_sampling_percent,
|
649
|
+
instr_sampler
|
553
650
|
)
|
554
651
|
end
|
555
652
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api public
|
4
|
+
# @since 1.6.0
|
5
|
+
module RedisQueuedLocks::Instrument::Sampler
|
6
|
+
# @return [Range]
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
# @since 1.6.0
|
10
|
+
SAMPLING_PERCENT_RANGE = (0..100)
|
11
|
+
|
12
|
+
class << self
|
13
|
+
# Super simple probalistic function based on the `weight` of <true>/<false> values.
|
14
|
+
# Requires the <percent> parameter as the required percent of <true> values sampled.
|
15
|
+
#
|
16
|
+
# @param sampling_percent [Integer]
|
17
|
+
# - percent of <true> values in range of 0..100;
|
18
|
+
# @return [Boolean]
|
19
|
+
# - <true> for <sampling_percent>% of invocations (and <false> for the rest invocations)
|
20
|
+
#
|
21
|
+
# @api public
|
22
|
+
# @since 1.6.0
|
23
|
+
def sampling_happened?(sampling_percent)
|
24
|
+
sampling_percent >= SecureRandom.rand(SAMPLING_PERCENT_RANGE)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -2,11 +2,58 @@
|
|
2
2
|
|
3
3
|
# @api public
|
4
4
|
# @since 1.0.0
|
5
|
+
# @version 1.6.0
|
5
6
|
module RedisQueuedLocks::Instrument
|
6
7
|
require_relative 'instrument/void_notifier'
|
7
8
|
require_relative 'instrument/active_support'
|
9
|
+
require_relative 'instrument/sampler'
|
8
10
|
|
9
11
|
class << self
|
12
|
+
# @param instr_sampling_enabled [Boolean]
|
13
|
+
# @param instr_sampling_percent [Integer]
|
14
|
+
# @param instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
15
|
+
# @return [Boolean]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
# @since 1.6.0
|
19
|
+
def should_instrument?(instr_sampling_enabled, instr_sampling_percent, instr_sampler)
|
20
|
+
return true unless instr_sampling_enabled
|
21
|
+
instr_sampler.sampling_happened?(instr_sampling_percent)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
25
|
+
# @return [Boolean]
|
26
|
+
#
|
27
|
+
# @api private
|
28
|
+
# @since 1.6.0
|
29
|
+
def valid_sampler?(sampler)
|
30
|
+
return false unless sampler.respond_to?(:sampling_happened?)
|
31
|
+
|
32
|
+
m_obj = sampler.method(:sampling_happened?)
|
33
|
+
m_sig = m_obj.parameters
|
34
|
+
|
35
|
+
# NOTE:
|
36
|
+
# Required method signature (sampling_percent)
|
37
|
+
# => [[:req, :sampling_percent]]
|
38
|
+
# => [[:opt, :sampling_percent]]
|
39
|
+
# => [[:req, :sampling_percent], [:block, :block]]
|
40
|
+
# => [[:opt, :sampling_percent], [:block, :block]]
|
41
|
+
if m_sig.size == 1
|
42
|
+
prm = m_sig[0][0]
|
43
|
+
prm == :req || prm == :opt
|
44
|
+
elsif m_sig.size == 2
|
45
|
+
f_prm = m_sig[0][0]
|
46
|
+
s_prm = m_sign[1][0]
|
47
|
+
|
48
|
+
# rubocop:disable Layout/MultilineOperationIndentation
|
49
|
+
f_prm == :req && s_prm == :block ||
|
50
|
+
f_prm == :opt && s_prm == :block
|
51
|
+
# rubocop:enable Layout/MultilineOperationIndentation
|
52
|
+
else
|
53
|
+
false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
10
57
|
# @param instrumenter [Class,Module,Object]
|
11
58
|
# @return [Boolean]
|
12
59
|
#
|
@@ -1,8 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# @api
|
3
|
+
# @api public
|
4
4
|
# @since 1.5.0
|
5
5
|
module RedisQueuedLocks::Logging::Sampler
|
6
|
+
# @return [Range]
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
# @since 1.6.0
|
10
|
+
SAMPLING_PERCENT_RANGE = (0..100)
|
11
|
+
|
6
12
|
class << self
|
7
13
|
# Super simple probalistic function based on the `weight` of <true>/<false> values.
|
8
14
|
# Requires the <percent> parameter as the required percent of <true> values sampled.
|
@@ -12,10 +18,11 @@ module RedisQueuedLocks::Logging::Sampler
|
|
12
18
|
# @return [Boolean]
|
13
19
|
# - <true> for <sampling_percent>% of invocations (and <false> for the rest invocations)
|
14
20
|
#
|
15
|
-
# @api
|
21
|
+
# @api public
|
16
22
|
# @since 1.5.0
|
23
|
+
# @version 1.6.0
|
17
24
|
def sampling_happened?(sampling_percent)
|
18
|
-
sampling_percent >= SecureRandom.rand(
|
25
|
+
sampling_percent >= SecureRandom.rand(SAMPLING_PERCENT_RANGE)
|
19
26
|
end
|
20
27
|
end
|
21
28
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# frozen_string_literal: true
|
data/redis_queued_locks.gemspec
CHANGED
@@ -10,9 +10,29 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.authors = ['Rustam Ibragimov']
|
11
11
|
spec.email = ['iamdaiver@gmail.com']
|
12
12
|
|
13
|
-
spec.summary
|
14
|
-
|
15
|
-
|
13
|
+
spec.summary =
|
14
|
+
'Distributed locks with "prioritized lock acquisition queue" ' \
|
15
|
+
'capabilities based on the Redis Database.'
|
16
|
+
|
17
|
+
spec.description =
|
18
|
+
'Distributed locks with "prioritized lock acquisition queue" capabilities ' \
|
19
|
+
'based on the Redis Database. ' \
|
20
|
+
# ---
|
21
|
+
'Each lock request is put into the request queue ' \
|
22
|
+
"(each lock is hosted by it's own queue separately from other queues) and processed " \
|
23
|
+
'in order of their priority (FIFO). ' \
|
24
|
+
# ---
|
25
|
+
'Each lock request lives some period of time (RTTL) ' \
|
26
|
+
'(with requeue capabilities) which guarantees the request queue will never be stacked. ' \
|
27
|
+
# ---
|
28
|
+
'In addition to the classic `queued` (FIFO) strategy RQL supports ' \
|
29
|
+
'`random` (RANDOM) lock obtaining strategy when any acquirer from the lock queue ' \
|
30
|
+
'can obtain the lock regardless the position in the queue. ' \
|
31
|
+
# ---
|
32
|
+
'Provides flexible invocation flow, parametrized limits ' \
|
33
|
+
'(lock request ttl, lock ttl, queue ttl, lock attempts limit, fast failing, etc), ' \
|
34
|
+
'logging and instrumentation.'
|
35
|
+
|
16
36
|
spec.homepage = 'https://github.com/0exp/redis_queued_locks'
|
17
37
|
spec.license = 'MIT'
|
18
38
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis_queued_locks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rustam Ibragimov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis-client
|
@@ -38,8 +38,8 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.28'
|
41
|
-
description: Distributed locks with "lock acquisition queue" capabilities
|
42
|
-
the Redis Database.
|
41
|
+
description: 'Distributed locks with "prioritized lock acquisition queue" capabilities
|
42
|
+
based on the Redis Database. '
|
43
43
|
email:
|
44
44
|
- iamdaiver@gmail.com
|
45
45
|
executables: []
|
@@ -58,9 +58,15 @@ files:
|
|
58
58
|
- lib/redis_queued_locks/acquier.rb
|
59
59
|
- lib/redis_queued_locks/acquier/acquire_lock.rb
|
60
60
|
- lib/redis_queued_locks/acquier/acquire_lock/delay_execution.rb
|
61
|
+
- lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue.rb
|
62
|
+
- lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue/log_visitor.rb
|
63
|
+
- lib/redis_queued_locks/acquier/acquire_lock/instr_visitor.rb
|
64
|
+
- lib/redis_queued_locks/acquier/acquire_lock/log_visitor.rb
|
61
65
|
- lib/redis_queued_locks/acquier/acquire_lock/try_to_lock.rb
|
66
|
+
- lib/redis_queued_locks/acquier/acquire_lock/try_to_lock/log_visitor.rb
|
62
67
|
- lib/redis_queued_locks/acquier/acquire_lock/with_acq_timeout.rb
|
63
68
|
- lib/redis_queued_locks/acquier/acquire_lock/yield_expire.rb
|
69
|
+
- lib/redis_queued_locks/acquier/acquire_lock/yield_expire/log_visitor.rb
|
64
70
|
- lib/redis_queued_locks/acquier/clear_dead_requests.rb
|
65
71
|
- lib/redis_queued_locks/acquier/extend_lock_ttl.rb
|
66
72
|
- lib/redis_queued_locks/acquier/is_locked.rb
|
@@ -79,6 +85,7 @@ files:
|
|
79
85
|
- lib/redis_queued_locks/errors.rb
|
80
86
|
- lib/redis_queued_locks/instrument.rb
|
81
87
|
- lib/redis_queued_locks/instrument/active_support.rb
|
88
|
+
- lib/redis_queued_locks/instrument/sampler.rb
|
82
89
|
- lib/redis_queued_locks/instrument/void_notifier.rb
|
83
90
|
- lib/redis_queued_locks/logging.rb
|
84
91
|
- lib/redis_queued_locks/logging/sampler.rb
|
@@ -86,6 +93,7 @@ files:
|
|
86
93
|
- lib/redis_queued_locks/resource.rb
|
87
94
|
- lib/redis_queued_locks/utilities.rb
|
88
95
|
- lib/redis_queued_locks/version.rb
|
96
|
+
- lib/redis_queued_locks/watcher.rb
|
89
97
|
- redis_queued_locks.gemspec
|
90
98
|
homepage: https://github.com/0exp/redis_queued_locks
|
91
99
|
licenses:
|
@@ -109,8 +117,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
117
|
- !ruby/object:Gem::Version
|
110
118
|
version: '0'
|
111
119
|
requirements: []
|
112
|
-
rubygems_version: 3.
|
120
|
+
rubygems_version: 3.3.7
|
113
121
|
signing_key:
|
114
122
|
specification_version: 4
|
115
|
-
summary:
|
123
|
+
summary: Distributed locks with "prioritized lock acquisition queue" capabilities
|
124
|
+
based on the Redis Database.
|
116
125
|
test_files: []
|