redis_queued_locks 1.5.0 → 1.7.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/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: []
|