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
@@ -2,16 +2,20 @@
|
|
2
2
|
|
3
3
|
# @api private
|
4
4
|
# @since 1.0.0
|
5
|
+
# @version 1.7.0
|
5
6
|
# rubocop:disable Metrics/ModuleLength
|
6
7
|
# rubocop:disable Metrics/MethodLength
|
7
8
|
# rubocop:disable Metrics/ClassLength
|
8
9
|
# rubocop:disable Metrics/BlockNesting
|
9
10
|
# rubocop:disable Style/IfInsideElse
|
10
11
|
module RedisQueuedLocks::Acquier::AcquireLock
|
12
|
+
require_relative 'acquire_lock/log_visitor'
|
13
|
+
require_relative 'acquire_lock/instr_visitor'
|
11
14
|
require_relative 'acquire_lock/delay_execution'
|
12
15
|
require_relative 'acquire_lock/with_acq_timeout'
|
13
16
|
require_relative 'acquire_lock/yield_expire'
|
14
17
|
require_relative 'acquire_lock/try_to_lock'
|
18
|
+
require_relative 'acquire_lock/dequeue_from_lock_queue'
|
15
19
|
|
16
20
|
# @since 1.0.0
|
17
21
|
extend TryToLock
|
@@ -21,8 +25,8 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
21
25
|
extend YieldExpire
|
22
26
|
# @since 1.0.0
|
23
27
|
extend WithAcqTimeout
|
24
|
-
# @since 1.
|
25
|
-
extend
|
28
|
+
# @since 1.7.0
|
29
|
+
extend DequeueFromLockQueue
|
26
30
|
|
27
31
|
class << self
|
28
32
|
# @param redis [RedisClient]
|
@@ -86,20 +90,51 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
86
90
|
# - `:extendable_work_through`;
|
87
91
|
# - `:wait_for_lock`;
|
88
92
|
# - `:dead_locking`;
|
93
|
+
# @option access_strategy [Symbol]
|
94
|
+
# - The way in which the lock will be obtained;
|
95
|
+
# - By default it uses `:queued` strategy;
|
96
|
+
# - Supports following strategies:
|
97
|
+
# - `:queued` (FIFO): the classic queued behavior (default), your lock will be
|
98
|
+
# obitaned if you are first in queue and the required lock is free;
|
99
|
+
# - `:random` (RANDOM): obtain a lock without checking the positions in the queue
|
100
|
+
# (but with checking the limist, retries, timeouts and so on). if lock is
|
101
|
+
# free to obtain - it will be obtained;
|
102
|
+
# - pre-configured in `config[:default_access_strategy]`;
|
89
103
|
# @option log_sampling_enabled [Boolean]
|
90
|
-
# -
|
91
|
-
# -
|
92
|
-
#
|
93
|
-
# - You can provide your own sampler via config[:log_sampler] config and :sampler option
|
94
|
-
# (see `RedisQueuedLocks::Logging::Sampler` for examples);
|
95
|
-
# - The spread of guaranteed percent is approximately +13% (rand method spread);
|
96
|
-
# - Take an effect when <log_sampling_enabled> parameter has <true> value
|
97
|
-
# (when log sampling is enabled);
|
104
|
+
# - enables <log sampling>: only the configured percent of RQL cases will be logged;
|
105
|
+
# - disabled by default;
|
106
|
+
# - works in tandem with <config.log_sampling_percent and <log.sampler>;
|
98
107
|
# @option log_sampling_percent [Integer]
|
99
|
-
# -
|
100
|
-
# -
|
101
|
-
#
|
108
|
+
# - the percent of cases that should be logged;
|
109
|
+
# - take an effect when <config.log_sampling_enalbed> is true;
|
110
|
+
# - works in tandem with <config.log_sampling_enabled> and <config.log_sampler> configs;
|
102
111
|
# @option log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
112
|
+
# - percent-based log sampler that decides should be RQL case logged or not;
|
113
|
+
# - works in tandem with <config.log_sampling_enabled> and
|
114
|
+
# <config.log_sampling_percent> configs;
|
115
|
+
# - based on the ultra simple percent-based (weight-based) algorithm that uses
|
116
|
+
# SecureRandom.rand method so the algorithm error is ~(0%..13%);
|
117
|
+
# - you can provide your own log sampler with bettter algorithm that should realize
|
118
|
+
# `sampling_happened?(percent) => boolean` interface
|
119
|
+
# (see `RedisQueuedLocks::Logging::Sampler` for example);
|
120
|
+
# @option instr_sampling_enabled [Boolean]
|
121
|
+
# - enables <instrumentaion sampling>: only the configured percent
|
122
|
+
# of RQL cases will be instrumented;
|
123
|
+
# - disabled by default;
|
124
|
+
# - works in tandem with <config.instr_sampling_percent and <log.instr_sampler>;
|
125
|
+
# @option instr_sampling_percent [Integer]
|
126
|
+
# - the percent of cases that should be instrumented;
|
127
|
+
# - take an effect when <config.instr_sampling_enalbed> is true;
|
128
|
+
# - works in tandem with <config.instr_sampling_enabled> and <config.instr_sampler> configs;
|
129
|
+
# @option instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
130
|
+
# - percent-based log sampler that decides should be RQL case instrumented or not;
|
131
|
+
# - works in tandem with <config.instr_sampling_enabled> and
|
132
|
+
# <config.instr_sampling_percent> configs;
|
133
|
+
# - based on the ultra simple percent-based (weight-based) algorithm that uses
|
134
|
+
# SecureRandom.rand method so the algorithm error is ~(0%..13%);
|
135
|
+
# - you can provide your own log sampler with bettter algorithm that should realize
|
136
|
+
# `sampling_happened?(percent) => boolean` interface
|
137
|
+
# (see `RedisQueuedLocks::Instrument::Sampler` for example);
|
103
138
|
# @param [Block]
|
104
139
|
# A block of code that should be executed after the successfully acquired lock.
|
105
140
|
# @return [RedisQueuedLocks::Data,Hash<Symbol,Any>,yield]
|
@@ -108,7 +143,7 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
108
143
|
#
|
109
144
|
# @api private
|
110
145
|
# @since 1.0.0
|
111
|
-
# @version 1.
|
146
|
+
# @version 1.7.0
|
112
147
|
def acquire_lock(
|
113
148
|
redis,
|
114
149
|
lock_name,
|
@@ -132,9 +167,13 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
132
167
|
logger:,
|
133
168
|
log_lock_try:,
|
134
169
|
conflict_strategy:,
|
170
|
+
access_strategy:,
|
135
171
|
log_sampling_enabled:,
|
136
172
|
log_sampling_percent:,
|
137
173
|
log_sampler:,
|
174
|
+
instr_sampling_enabled:,
|
175
|
+
instr_sampling_percent:,
|
176
|
+
instr_sampler:,
|
138
177
|
&block
|
139
178
|
)
|
140
179
|
# Step 0: Prevent argument type incompatabilities
|
@@ -187,6 +226,11 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
187
226
|
log_sampling_percent,
|
188
227
|
log_sampler
|
189
228
|
)
|
229
|
+
instr_sampled = RedisQueuedLocks::Instrument.should_instrument?(
|
230
|
+
instr_sampling_enabled,
|
231
|
+
instr_sampling_percent,
|
232
|
+
instr_sampler
|
233
|
+
)
|
190
234
|
|
191
235
|
# Step X: intermediate result observer
|
192
236
|
acq_process = {
|
@@ -207,18 +251,16 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
207
251
|
lock_key_queue,
|
208
252
|
queue_ttl,
|
209
253
|
acquier_id,
|
210
|
-
|
254
|
+
access_strategy,
|
255
|
+
log_sampled,
|
256
|
+
instr_sampled
|
211
257
|
)
|
212
258
|
end
|
213
259
|
|
214
|
-
|
215
|
-
logger
|
216
|
-
|
217
|
-
|
218
|
-
"queue_ttl => #{queue_ttl} " \
|
219
|
-
"acq_id => '#{acquier_id}'"
|
220
|
-
end
|
221
|
-
end if log_sampled
|
260
|
+
LogVisitor.start_lock_obtaining(
|
261
|
+
logger, log_sampled,
|
262
|
+
lock_key, queue_ttl, acquier_id, access_strategy
|
263
|
+
)
|
222
264
|
|
223
265
|
# Step 2: try to lock with timeout
|
224
266
|
with_acq_timeout(timeout, lock_key, raise_errors, on_timeout: acq_dequeue) do
|
@@ -226,28 +268,21 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
226
268
|
|
227
269
|
# Step 2.1: cyclically try to obtain the lock
|
228
270
|
while acq_process[:should_try]
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
"acq_id => '{#{acquier_id}'"
|
235
|
-
end
|
236
|
-
end if log_sampled
|
271
|
+
|
272
|
+
LogVisitor.start_try_to_lock_cycle(
|
273
|
+
logger, log_sampled,
|
274
|
+
lock_key, queue_ttl, acquier_id, access_strategy
|
275
|
+
)
|
237
276
|
|
238
277
|
# Step 2.X: check the actual score: is it in queue ttl limit or not?
|
239
278
|
if RedisQueuedLocks::Resource.dead_score_reached?(acquier_position, queue_ttl)
|
240
279
|
# Step 2.X.X: dead score reached => re-queue the lock request with the new score;
|
241
280
|
acquier_position = RedisQueuedLocks::Resource.calc_initial_acquier_position
|
242
281
|
|
243
|
-
|
244
|
-
logger
|
245
|
-
|
246
|
-
|
247
|
-
"queue_ttl => #{queue_ttl} " \
|
248
|
-
"acq_id => '#{acquier_id}'"
|
249
|
-
end
|
250
|
-
end if log_sampled
|
282
|
+
LogVisitor.dead_score_reached__reset_acquier_position(
|
283
|
+
logger, log_sampled,
|
284
|
+
lock_key, queue_ttl, acquier_id, access_strategy
|
285
|
+
)
|
251
286
|
end
|
252
287
|
|
253
288
|
try_to_lock(
|
@@ -262,8 +297,10 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
262
297
|
queue_ttl,
|
263
298
|
fail_fast,
|
264
299
|
conflict_strategy,
|
300
|
+
access_strategy,
|
265
301
|
meta,
|
266
|
-
log_sampled
|
302
|
+
log_sampled,
|
303
|
+
instr_sampled
|
267
304
|
) => { ok:, result: }
|
268
305
|
|
269
306
|
acq_end_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond)
|
@@ -278,72 +315,38 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
278
315
|
# Step X: (instrumentation)
|
279
316
|
if acq_process[:result][:process] == :extendable_conflict_work_through
|
280
317
|
# instrumetnation: (reentrant lock with ttl extension)
|
281
|
-
|
282
|
-
logger
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
run_non_critical do
|
292
|
-
instrumenter.notify('redis_queued_locks.extendable_reentrant_lock_obtained', {
|
293
|
-
lock_key: result[:lock_key],
|
294
|
-
ttl: result[:ttl],
|
295
|
-
acq_id: result[:acq_id],
|
296
|
-
ts: result[:ts],
|
297
|
-
acq_time: acq_time,
|
298
|
-
instrument:
|
299
|
-
})
|
300
|
-
end
|
318
|
+
LogVisitor.extendable_reentrant_lock_obtained(
|
319
|
+
logger, log_sampled,
|
320
|
+
result[:lock_key], queue_ttl, acquier_id, acq_time, access_strategy
|
321
|
+
)
|
322
|
+
InstrVisitor.extendable_reentrant_lock_obtained(
|
323
|
+
instrumenter, instr_sampled,
|
324
|
+
result[:lock_key], result[:ttl], result[:acq_id], result[:ts], acq_time,
|
325
|
+
instrument
|
326
|
+
)
|
301
327
|
elsif acq_process[:result][:process] == :conflict_work_through
|
302
328
|
# instrumetnation: (reentrant lock without ttl extension)
|
303
|
-
|
304
|
-
logger
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
run_non_critical do
|
314
|
-
instrumenter.notify('redis_queued_locks.reentrant_lock_obtained', {
|
315
|
-
lock_key: result[:lock_key],
|
316
|
-
ttl: result[:ttl],
|
317
|
-
acq_id: result[:acq_id],
|
318
|
-
ts: result[:ts],
|
319
|
-
acq_time: acq_time,
|
320
|
-
instrument:
|
321
|
-
})
|
322
|
-
end
|
329
|
+
LogVisitor.reentrant_lock_obtained(
|
330
|
+
logger, log_sampled,
|
331
|
+
result[:lock_key], queue_ttl, acquier_id, acq_time, access_strategy
|
332
|
+
)
|
333
|
+
InstrVisitor.reentrant_lock_obtained(
|
334
|
+
instrumenter, instr_sampled,
|
335
|
+
result[:lock_key], result[:ttl], result[:acq_id], result[:ts], acq_time,
|
336
|
+
instrument
|
337
|
+
)
|
323
338
|
else
|
324
339
|
# instrumentation: (classic lock obtain)
|
325
340
|
# NOTE: classic is: acq_process[:result][:process] == :lock_obtaining
|
326
|
-
|
327
|
-
logger
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
# Step X (instrumentation): lock obtained
|
337
|
-
run_non_critical do
|
338
|
-
instrumenter.notify('redis_queued_locks.lock_obtained', {
|
339
|
-
lock_key: result[:lock_key],
|
340
|
-
ttl: result[:ttl],
|
341
|
-
acq_id: result[:acq_id],
|
342
|
-
ts: result[:ts],
|
343
|
-
acq_time: acq_time,
|
344
|
-
instrument:
|
345
|
-
})
|
346
|
-
end
|
341
|
+
LogVisitor.lock_obtained(
|
342
|
+
logger, log_sampled,
|
343
|
+
result[:lock_key], queue_ttl, acquier_id, acq_time, access_strategy
|
344
|
+
)
|
345
|
+
InstrVisitor.lock_obtained(
|
346
|
+
instrumenter, instr_sampled,
|
347
|
+
result[:lock_key], result[:ttl], result[:acq_id], result[:ts], acq_time,
|
348
|
+
instrument
|
349
|
+
)
|
347
350
|
end
|
348
351
|
|
349
352
|
# Step 2.1.a: successfully acquired => build the result
|
@@ -447,11 +450,13 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
447
450
|
logger,
|
448
451
|
lock_key,
|
449
452
|
acquier_id,
|
453
|
+
access_strategy,
|
450
454
|
timed,
|
451
455
|
ttl_shift,
|
452
456
|
ttl,
|
453
457
|
queue_ttl,
|
454
458
|
log_sampled,
|
459
|
+
instr_sampled,
|
455
460
|
should_expire, # NOTE: should expire the lock after the block execution
|
456
461
|
should_decrease, # NOTE: should decrease the lock ttl in reentrant locks?
|
457
462
|
&block
|
@@ -467,30 +472,30 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
467
472
|
if acq_process[:result][:process] == :extendable_conflict_work_through ||
|
468
473
|
acq_process[:result][:process] == :conflict_work_through
|
469
474
|
# Step X (instrumentation): reentrant_lock_hold_completes
|
470
|
-
|
471
|
-
instrumenter
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
475
|
+
InstrVisitor.reentrant_lock_hold_completes(
|
476
|
+
instrumenter,
|
477
|
+
instr_sampled,
|
478
|
+
acq_process[:lock_info][:lock_key],
|
479
|
+
acq_process[:lock_info][:ttl],
|
480
|
+
acq_process[:lock_info][:acq_id],
|
481
|
+
acq_process[:lock_info][:ts],
|
482
|
+
acq_process[:acq_time],
|
483
|
+
acq_process[:hold_time],
|
484
|
+
instrument
|
485
|
+
)
|
481
486
|
else
|
482
487
|
# Step X (instrumentation): lock_hold_and_release
|
483
|
-
|
484
|
-
instrumenter
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
488
|
+
InstrVisitor.lock_hold_and_release(
|
489
|
+
instrumenter,
|
490
|
+
instr_sampled,
|
491
|
+
acq_process[:lock_info][:lock_key],
|
492
|
+
acq_process[:lock_info][:ttl],
|
493
|
+
acq_process[:lock_info][:acq_id],
|
494
|
+
acq_process[:lock_info][:ts],
|
495
|
+
acq_process[:lock_info][:lock_key],
|
496
|
+
acq_process[:acq_time],
|
497
|
+
instrument
|
498
|
+
)
|
494
499
|
end
|
495
500
|
end
|
496
501
|
else
|
@@ -13,10 +13,14 @@ module RedisQueuedLocks::Acquier::ClearDeadRequests
|
|
13
13
|
# @param log_sampling_enabled [Boolean]
|
14
14
|
# @param log_sampling_percent [Integer]
|
15
15
|
# @param log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
16
|
+
# @param instr_sampling_enabled [Boolean]
|
17
|
+
# @param instr_sampling_percent [Integer]
|
18
|
+
# @param instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
16
19
|
# @return [Hash<Symbol,Boolean|Hash<Symbol,Set<String>>>]
|
17
20
|
#
|
18
21
|
# @api private
|
19
22
|
# @since 1.0.0
|
23
|
+
# @version 1.6.0
|
20
24
|
def clear_dead_requests(
|
21
25
|
redis_client,
|
22
26
|
scan_size,
|
@@ -26,7 +30,10 @@ module RedisQueuedLocks::Acquier::ClearDeadRequests
|
|
26
30
|
instrument,
|
27
31
|
log_sampling_enabled,
|
28
32
|
log_sampling_percent,
|
29
|
-
log_sampler
|
33
|
+
log_sampler,
|
34
|
+
instr_sampling_enabled,
|
35
|
+
instr_sampling_percent,
|
36
|
+
instr_sampler
|
30
37
|
)
|
31
38
|
dead_score = RedisQueuedLocks::Resource.acquier_dead_score(dead_ttl / 1_000.0)
|
32
39
|
|
@@ -17,22 +17,32 @@ module RedisQueuedLocks::Acquier::ExtendLockTTL
|
|
17
17
|
# @param lock_name [String]
|
18
18
|
# @param milliseconds [Integer]
|
19
19
|
# @param logger [::Logger,#debug]
|
20
|
+
# @param instrumenter [#notify]
|
21
|
+
# @param instrument [NilClass,Any]
|
20
22
|
# @param log_sampling_enabled [Boolean]
|
21
23
|
# @param log_sampling_percent [Integer]
|
22
24
|
# @param log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
25
|
+
# @param instr_sampling_enabled [Boolean]
|
26
|
+
# @param instr_sampling_percent [Integer]
|
27
|
+
# @param instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
23
28
|
# @return [Hash<Symbol,Boolean|Symbol>]
|
24
29
|
#
|
25
30
|
# @api private
|
26
31
|
# @since 1.0.0
|
27
|
-
# @version 1.
|
32
|
+
# @version 1.6.0
|
28
33
|
def extend_lock_ttl(
|
29
34
|
redis_client,
|
30
35
|
lock_name,
|
31
36
|
milliseconds,
|
32
37
|
logger,
|
38
|
+
instrumenter,
|
39
|
+
instrument,
|
33
40
|
log_sampling_enabled,
|
34
41
|
log_sampling_percent,
|
35
|
-
log_sampler
|
42
|
+
log_sampler,
|
43
|
+
instr_sampling_enabled,
|
44
|
+
instr_sampling_percent,
|
45
|
+
instr_sampler
|
36
46
|
)
|
37
47
|
lock_key = RedisQueuedLocks::Resource.prepare_lock_key(lock_name)
|
38
48
|
|
@@ -24,19 +24,46 @@ module RedisQueuedLocks::Acquier::ReleaseAllLocks
|
|
24
24
|
# - Custom instrumentation data wich will be passed to the instrumenter's payload
|
25
25
|
# with :instrument key;
|
26
26
|
# @param log_sampling_enabled [Boolean]
|
27
|
-
# -
|
28
|
-
# -
|
27
|
+
# - enables <log sampling>: only the configured percent of RQL cases will be logged;
|
28
|
+
# - disabled by default;
|
29
|
+
# - works in tandem with <config.log_sampling_percent and <log.sampler>;
|
29
30
|
# @param log_sampling_percent [Integer]
|
30
|
-
# -
|
31
|
-
# -
|
32
|
-
#
|
31
|
+
# - the percent of cases that should be logged;
|
32
|
+
# - take an effect when <config.log_sampling_enalbed> is true;
|
33
|
+
# - works in tandem with <config.log_sampling_enabled> and <config.log_sampler> configs;
|
33
34
|
# @param log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
35
|
+
# - percent-based log sampler that decides should be RQL case logged or not;
|
36
|
+
# - works in tandem with <config.log_sampling_enabled> and
|
37
|
+
# <config.log_sampling_percent> configs;
|
38
|
+
# - based on the ultra simple percent-based (weight-based) algorithm that uses
|
39
|
+
# SecureRandom.rand method so the algorithm error is ~(0%..13%);
|
40
|
+
# - you can provide your own log sampler with bettter algorithm that should realize
|
41
|
+
# `sampling_happened?(percent) => boolean` interface
|
42
|
+
# (see `RedisQueuedLocks::Logging::Sampler` for example);
|
43
|
+
# @param instr_sampling_enabled [Boolean]
|
44
|
+
# - enables <instrumentaion sampling>: only the configured percent
|
45
|
+
# of RQL cases will be instrumented;
|
46
|
+
# - disabled by default;
|
47
|
+
# - works in tandem with <config.instr_sampling_percent and <log.instr_sampler>;
|
48
|
+
# @param instr_sampling_percent [Integer]
|
49
|
+
# - the percent of cases that should be instrumented;
|
50
|
+
# - take an effect when <config.instr_sampling_enalbed> is true;
|
51
|
+
# - works in tandem with <config.instr_sampling_enabled> and <config.instr_sampler> configs;
|
52
|
+
# @param instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
53
|
+
# - percent-based log sampler that decides should be RQL case instrumented or not;
|
54
|
+
# - works in tandem with <config.instr_sampling_enabled> and
|
55
|
+
# <config.instr_sampling_percent> configs;
|
56
|
+
# - based on the ultra simple percent-based (weight-based) algorithm that uses
|
57
|
+
# SecureRandom.rand method so the algorithm error is ~(0%..13%);
|
58
|
+
# - you can provide your own log sampler with bettter algorithm that should realize
|
59
|
+
# `sampling_happened?(percent) => boolean` interface
|
60
|
+
# (see `RedisQueuedLocks::Instrument::Sampler` for example);
|
34
61
|
# @return [RedisQueuedLocks::Data,Hash<Symbol,Any>]
|
35
62
|
# Format: { ok: true, result: Hash<Symbol,Numeric> }
|
36
63
|
#
|
37
64
|
# @api private
|
38
65
|
# @since 1.0.0
|
39
|
-
# @version 1.
|
66
|
+
# @version 1.6.0
|
40
67
|
def release_all_locks(
|
41
68
|
redis,
|
42
69
|
batch_size,
|
@@ -45,7 +72,10 @@ module RedisQueuedLocks::Acquier::ReleaseAllLocks
|
|
45
72
|
instrument,
|
46
73
|
log_sampling_enabled,
|
47
74
|
log_sampling_percent,
|
48
|
-
log_sampler
|
75
|
+
log_sampler,
|
76
|
+
instr_sampling_enabled,
|
77
|
+
instr_sampling_percent,
|
78
|
+
instr_sampler
|
49
79
|
)
|
50
80
|
rel_start_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond)
|
51
81
|
fully_release_all_locks(redis, batch_size) => { ok:, result: }
|
@@ -53,13 +83,19 @@ module RedisQueuedLocks::Acquier::ReleaseAllLocks
|
|
53
83
|
rel_end_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond)
|
54
84
|
rel_time = ((rel_end_time - rel_start_time) / 1_000).ceil(2)
|
55
85
|
|
86
|
+
instr_sampled = RedisQueuedLocks::Instrument.should_instrument?(
|
87
|
+
instr_sampling_enabled,
|
88
|
+
instr_sampling_percent,
|
89
|
+
instr_sampler
|
90
|
+
)
|
91
|
+
|
56
92
|
run_non_critical do
|
57
93
|
instrumenter.notify('redis_queued_locks.explicit_all_locks_release', {
|
58
94
|
at: time_at,
|
59
95
|
rel_time: rel_time,
|
60
96
|
rel_key_cnt: result[:rel_key_cnt]
|
61
97
|
})
|
62
|
-
end
|
98
|
+
end if instr_sampled
|
63
99
|
|
64
100
|
RedisQueuedLocks::Data[
|
65
101
|
ok: true,
|
@@ -24,25 +24,47 @@ module RedisQueuedLocks::Acquier::ReleaseLock
|
|
24
24
|
# - Logger object used from `configuration` layer (see config[:logger]);
|
25
25
|
# - See RedisQueuedLocks::Logging::VoidLogger for example;
|
26
26
|
# @param log_sampling_enabled [Boolean]
|
27
|
-
# -
|
28
|
-
# -
|
29
|
-
#
|
30
|
-
# - You can provide your own sampler via config[:log_sampler] config and :sampler option
|
31
|
-
# (see `RedisQueuedLocks::Logging::Sampler` for examples);
|
32
|
-
# - The spread of guaranteed percent is approximately +13% (rand method spread);
|
33
|
-
# - Take an effect when <log_sampling_enabled> parameter has <true> value
|
34
|
-
# (when log sampling is enabled);
|
27
|
+
# - enables <log sampling>: only the configured percent of RQL cases will be logged;
|
28
|
+
# - disabled by default;
|
29
|
+
# - works in tandem with <config.log_sampling_percent and <log.sampler>;
|
35
30
|
# @param log_sampling_percent [Integer]
|
36
|
-
# -
|
37
|
-
# -
|
38
|
-
#
|
31
|
+
# - the percent of cases that should be logged;
|
32
|
+
# - take an effect when <config.log_sampling_enalbed> is true;
|
33
|
+
# - works in tandem with <config.log_sampling_enabled> and <config.log_sampler> configs;
|
39
34
|
# @param log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
35
|
+
# - percent-based log sampler that decides should be RQL case logged or not;
|
36
|
+
# - works in tandem with <config.log_sampling_enabled> and
|
37
|
+
# <config.log_sampling_percent> configs;
|
38
|
+
# - based on the ultra simple percent-based (weight-based) algorithm that uses
|
39
|
+
# SecureRandom.rand method so the algorithm error is ~(0%..13%);
|
40
|
+
# - you can provide your own log sampler with bettter algorithm that should realize
|
41
|
+
# `sampling_happened?(percent) => boolean` interface
|
42
|
+
# (see `RedisQueuedLocks::Logging::Sampler` for example);
|
43
|
+
# @param instr_sampling_enabled [Boolean]
|
44
|
+
# - enables <instrumentaion sampling>: only the configured percent
|
45
|
+
# of RQL cases will be instrumented;
|
46
|
+
# - disabled by default;
|
47
|
+
# - works in tandem with <config.instr_sampling_percent and <log.instr_sampler>;
|
48
|
+
# @param instr_sampling_percent [Integer]
|
49
|
+
# - the percent of cases that should be instrumented;
|
50
|
+
# - take an effect when <config.instr_sampling_enalbed> is true;
|
51
|
+
# - works in tandem with <config.instr_sampling_enabled> and <config.instr_sampler> configs;
|
52
|
+
# @param instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
53
|
+
# - percent-based log sampler that decides should be RQL case instrumented or not;
|
54
|
+
# - works in tandem with <config.instr_sampling_enabled> and
|
55
|
+
# <config.instr_sampling_percent> configs;
|
56
|
+
# - based on the ultra simple percent-based (weight-based) algorithm that uses
|
57
|
+
# SecureRandom.rand method so the algorithm error is ~(0%..13%);
|
58
|
+
# - you can provide your own log sampler with bettter algorithm that should realize
|
59
|
+
# `sampling_happened?(percent) => boolean` interface
|
60
|
+
# (see `RedisQueuedLocks::Instrument::Sampler` for example);
|
40
61
|
# @return [RedisQueuedLocks::Data,Hash<Symbol,Boolean<Hash<Symbol,Numeric|String|Symbol>>]
|
41
62
|
# Format: { ok: true/false, result: Hash<Symbol,Numeric|String|Symbol> }
|
42
63
|
#
|
43
64
|
# @api private
|
44
65
|
# @since 1.0.0
|
45
|
-
# @version 1.
|
66
|
+
# @version 1.6.0
|
67
|
+
# rubocop:disable Metrics/MethodLength
|
46
68
|
def release_lock(
|
47
69
|
redis,
|
48
70
|
lock_name,
|
@@ -50,7 +72,10 @@ module RedisQueuedLocks::Acquier::ReleaseLock
|
|
50
72
|
logger,
|
51
73
|
log_sampling_enabled,
|
52
74
|
log_sampling_percent,
|
53
|
-
log_sampler
|
75
|
+
log_sampler,
|
76
|
+
instr_sampling_enabled,
|
77
|
+
instr_sampling_percent,
|
78
|
+
instr_sampler
|
54
79
|
)
|
55
80
|
lock_key = RedisQueuedLocks::Resource.prepare_lock_key(lock_name)
|
56
81
|
lock_key_queue = RedisQueuedLocks::Resource.prepare_lock_queue(lock_name)
|
@@ -61,6 +86,12 @@ module RedisQueuedLocks::Acquier::ReleaseLock
|
|
61
86
|
rel_end_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond)
|
62
87
|
rel_time = ((rel_end_time - rel_start_time) / 1_000).ceil(2)
|
63
88
|
|
89
|
+
instr_sampled = RedisQueuedLocks::Instrument.should_instrument?(
|
90
|
+
instr_sampling_enabled,
|
91
|
+
instr_sampling_percent,
|
92
|
+
instr_sampler
|
93
|
+
)
|
94
|
+
|
64
95
|
run_non_critical do
|
65
96
|
instrumenter.notify('redis_queued_locks.explicit_lock_release', {
|
66
97
|
lock_key: lock_key,
|
@@ -68,7 +99,7 @@ module RedisQueuedLocks::Acquier::ReleaseLock
|
|
68
99
|
rel_time: rel_time,
|
69
100
|
at: time_at
|
70
101
|
})
|
71
|
-
end
|
102
|
+
end if instr_sampled
|
72
103
|
|
73
104
|
RedisQueuedLocks::Data[
|
74
105
|
ok: true,
|
@@ -81,6 +112,7 @@ module RedisQueuedLocks::Acquier::ReleaseLock
|
|
81
112
|
}
|
82
113
|
]
|
83
114
|
end
|
115
|
+
# rubocop:enable Metrics/MethodLength
|
84
116
|
|
85
117
|
private
|
86
118
|
|