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
@@ -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
|
|