redis_queued_locks 1.7.0 → 1.9.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/.ruby-version +1 -1
- data/CHANGELOG.md +60 -1
- data/README.md +485 -46
- data/lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +4 -0
- data/lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue.rb +4 -1
- data/lib/redis_queued_locks/acquier/acquire_lock/instr_visitor.rb +20 -5
- data/lib/redis_queued_locks/acquier/acquire_lock/log_visitor.rb +24 -0
- data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock/log_visitor.rb +56 -0
- data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock.rb +37 -30
- data/lib/redis_queued_locks/acquier/acquire_lock/with_acq_timeout.rb +41 -7
- data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire/log_visitor.rb +8 -0
- data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire.rb +21 -9
- data/lib/redis_queued_locks/acquier/acquire_lock.rb +61 -22
- data/lib/redis_queued_locks/acquier/clear_dead_requests.rb +5 -1
- data/lib/redis_queued_locks/acquier/extend_lock_ttl.rb +5 -1
- data/lib/redis_queued_locks/acquier/lock_info.rb +4 -3
- data/lib/redis_queued_locks/acquier/locks.rb +2 -2
- data/lib/redis_queued_locks/acquier/queue_info.rb +2 -2
- data/lib/redis_queued_locks/acquier/release_all_locks.rb +12 -2
- data/lib/redis_queued_locks/acquier/release_lock.rb +12 -2
- data/lib/redis_queued_locks/client.rb +320 -10
- data/lib/redis_queued_locks/errors.rb +8 -0
- data/lib/redis_queued_locks/instrument.rb +8 -1
- data/lib/redis_queued_locks/logging.rb +8 -1
- data/lib/redis_queued_locks/resource.rb +59 -1
- data/lib/redis_queued_locks/swarm/acquirers.rb +44 -0
- data/lib/redis_queued_locks/swarm/flush_zombies.rb +133 -0
- data/lib/redis_queued_locks/swarm/probe_hosts.rb +69 -0
- data/lib/redis_queued_locks/swarm/redis_client_builder.rb +67 -0
- data/lib/redis_queued_locks/swarm/supervisor.rb +83 -0
- data/lib/redis_queued_locks/swarm/swarm_element/isolated.rb +287 -0
- data/lib/redis_queued_locks/swarm/swarm_element/threaded.rb +351 -0
- data/lib/redis_queued_locks/swarm/swarm_element.rb +8 -0
- data/lib/redis_queued_locks/swarm/zombie_info.rb +145 -0
- data/lib/redis_queued_locks/swarm.rb +241 -0
- data/lib/redis_queued_locks/utilities/lock.rb +22 -0
- data/lib/redis_queued_locks/utilities.rb +75 -0
- data/lib/redis_queued_locks/version.rb +2 -2
- data/lib/redis_queued_locks.rb +2 -0
- data/redis_queued_locks.gemspec +6 -10
- metadata +24 -6
- data/lib/redis_queued_locks/watcher.rb +0 -1
@@ -40,6 +40,9 @@ module RedisQueuedLocks::Acquier::ReleaseLock
|
|
40
40
|
# - you can provide your own log sampler with bettter algorithm that should realize
|
41
41
|
# `sampling_happened?(percent) => boolean` interface
|
42
42
|
# (see `RedisQueuedLocks::Logging::Sampler` for example);
|
43
|
+
# @param log_sample_this [Boolean]
|
44
|
+
# - marks the method that everything should be logged despite the enabled log sampling;
|
45
|
+
# - makes sense when log sampling is enabled;
|
43
46
|
# @param instr_sampling_enabled [Boolean]
|
44
47
|
# - enables <instrumentaion sampling>: only the configured percent
|
45
48
|
# of RQL cases will be instrumented;
|
@@ -58,6 +61,10 @@ module RedisQueuedLocks::Acquier::ReleaseLock
|
|
58
61
|
# - you can provide your own log sampler with bettter algorithm that should realize
|
59
62
|
# `sampling_happened?(percent) => boolean` interface
|
60
63
|
# (see `RedisQueuedLocks::Instrument::Sampler` for example);
|
64
|
+
# @param instr_sample_this [Boolean]
|
65
|
+
# - marks the method that everything should be instrumneted
|
66
|
+
# despite the enabled instrumentation sampling;
|
67
|
+
# - makes sense when instrumentation sampling is enabled;
|
61
68
|
# @return [RedisQueuedLocks::Data,Hash<Symbol,Boolean<Hash<Symbol,Numeric|String|Symbol>>]
|
62
69
|
# Format: { ok: true/false, result: Hash<Symbol,Numeric|String|Symbol> }
|
63
70
|
#
|
@@ -73,9 +80,11 @@ module RedisQueuedLocks::Acquier::ReleaseLock
|
|
73
80
|
log_sampling_enabled,
|
74
81
|
log_sampling_percent,
|
75
82
|
log_sampler,
|
83
|
+
log_sample_this,
|
76
84
|
instr_sampling_enabled,
|
77
85
|
instr_sampling_percent,
|
78
|
-
instr_sampler
|
86
|
+
instr_sampler,
|
87
|
+
instr_sample_this
|
79
88
|
)
|
80
89
|
lock_key = RedisQueuedLocks::Resource.prepare_lock_key(lock_name)
|
81
90
|
lock_key_queue = RedisQueuedLocks::Resource.prepare_lock_queue(lock_name)
|
@@ -84,10 +93,11 @@ module RedisQueuedLocks::Acquier::ReleaseLock
|
|
84
93
|
fully_release_lock(redis, lock_key, lock_key_queue) => { ok:, result: }
|
85
94
|
time_at = Time.now.to_f
|
86
95
|
rel_end_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond)
|
87
|
-
rel_time = ((rel_end_time - rel_start_time) / 1_000).ceil(2)
|
96
|
+
rel_time = ((rel_end_time - rel_start_time) / 1_000.0).ceil(2)
|
88
97
|
|
89
98
|
instr_sampled = RedisQueuedLocks::Instrument.should_instrument?(
|
90
99
|
instr_sampling_enabled,
|
100
|
+
instr_sample_this,
|
91
101
|
instr_sampling_percent,
|
92
102
|
instr_sampler
|
93
103
|
)
|
@@ -14,6 +14,7 @@ class RedisQueuedLocks::Client
|
|
14
14
|
setting :try_to_lock_timeout, 10 # NOTE: in seconds
|
15
15
|
setting :default_lock_ttl, 5_000 # NOTE: in milliseconds
|
16
16
|
setting :default_queue_ttl, 15 # NOTE: in seconds
|
17
|
+
setting :detailed_acq_timeout_error, false
|
17
18
|
setting :lock_release_batch_size, 100
|
18
19
|
setting :key_extraction_batch_size, 500
|
19
20
|
setting :instrumenter, RedisQueuedLocks::Instrument::VoidNotifier
|
@@ -31,12 +32,63 @@ class RedisQueuedLocks::Client
|
|
31
32
|
setting :instr_sampling_percent, 15
|
32
33
|
setting :instr_sampler, RedisQueuedLocks::Instrument::Sampler
|
33
34
|
|
35
|
+
setting :swarm do
|
36
|
+
setting :auto_swarm, false
|
37
|
+
setting :supervisor do
|
38
|
+
setting :liveness_probing_period, 2 # NOTE: in seconds
|
39
|
+
end
|
40
|
+
setting :probe_hosts do
|
41
|
+
setting :enabled_for_swarm, true
|
42
|
+
setting :redis_config do
|
43
|
+
setting :sentinel, false
|
44
|
+
setting :pooled, false
|
45
|
+
setting :config, {}
|
46
|
+
setting :pool_config, {}
|
47
|
+
end
|
48
|
+
setting :probe_period, 2 # NOTE: in seconds
|
49
|
+
end
|
50
|
+
setting :flush_zombies do
|
51
|
+
setting :enabled_for_swarm, true
|
52
|
+
setting :redis_config do
|
53
|
+
setting :sentinel, false
|
54
|
+
setting :pooled, false
|
55
|
+
setting :config, {}
|
56
|
+
setting :pool_config, {}
|
57
|
+
end
|
58
|
+
setting :zombie_ttl, 15_000 # NOTE: in milliseconds
|
59
|
+
setting :zombie_lock_scan_size, 500
|
60
|
+
setting :zombie_queue_scan_size, 500
|
61
|
+
setting :zombie_flush_period, 10 # NOTE: in seconds
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
validate('swarm.auto_swarm', :boolean)
|
66
|
+
validate('swarm.visor.liveness_probing_period', :integer)
|
67
|
+
|
68
|
+
validate('swarm.probe_hosts.enabled_for_swarm', :boolean)
|
69
|
+
validate('swarm.probe_hosts.redis_config.sentinel', :boolean)
|
70
|
+
validate('swarm.probe_hosts.redis_config.pooled', :boolean)
|
71
|
+
validate('swarm.probe_hosts.redis_config.config', :hash)
|
72
|
+
validate('swarm.probe_hosts.redis_config.pool_config', :hash)
|
73
|
+
validate('swarm.probe_hosts.probe_period', :integer)
|
74
|
+
|
75
|
+
validate('swarm.flush_zombies.enabled_for_swarm', :boolean)
|
76
|
+
validate('swarm.flush_zombies.redis_config.sentinel', :boolean)
|
77
|
+
validate('swarm.flush_zombies.redis_config.pooled', :boolean)
|
78
|
+
validate('swarm.flush_zombies.redis_config.config', :hash)
|
79
|
+
validate('swarm.flush_zombies.redis_config.pool_config', :hash)
|
80
|
+
validate('swarm.flush_zombies.zombie_ttl', :integer)
|
81
|
+
validate('swarm.flush_zombies.zombie_lock_scan_size', :integer)
|
82
|
+
validate('swarm.flush_zombies.zombie_queue_scan_size', :integer)
|
83
|
+
validate('swarm.flush_zombies.zombie_flush_period', :integer)
|
84
|
+
|
34
85
|
validate('retry_count') { |val| val == nil || (val.is_a?(::Integer) && val >= 0) }
|
35
86
|
validate('retry_delay') { |val| val.is_a?(::Integer) && val >= 0 }
|
36
87
|
validate('retry_jitter') { |val| val.is_a?(::Integer) && val >= 0 }
|
37
88
|
validate('try_to_lock_timeout') { |val| val == nil || (val.is_a?(::Integer) && val >= 0) }
|
38
89
|
validate('default_lock_tt', :integer)
|
39
90
|
validate('default_queue_ttl', :integer)
|
91
|
+
validate('detailed_acq_timeout_error', :boolean)
|
40
92
|
validate('lock_release_batch_size', :integer)
|
41
93
|
validate('instrumenter') { |val| RedisQueuedLocks::Instrument.valid_interface?(val) }
|
42
94
|
validate('uniq_identifier', :proc)
|
@@ -80,6 +132,12 @@ class RedisQueuedLocks::Client
|
|
80
132
|
# @since 1.0.0
|
81
133
|
attr_accessor :uniq_identity
|
82
134
|
|
135
|
+
# @return [RedisQueuedLocks::Swarm]
|
136
|
+
#
|
137
|
+
# @api private
|
138
|
+
# @since 1.9.0
|
139
|
+
attr_reader :swarm
|
140
|
+
|
83
141
|
# @param redis_client [RedisClient]
|
84
142
|
# Redis connection manager, which will be used for the lock acquierment and distribution.
|
85
143
|
# It should be an instance of RedisClient.
|
@@ -93,8 +151,118 @@ class RedisQueuedLocks::Client
|
|
93
151
|
configure(&configs)
|
94
152
|
@uniq_identity = config[:uniq_identifier].call
|
95
153
|
@redis_client = redis_client
|
154
|
+
@swarm = RedisQueuedLocks::Swarm.new(self).tap { |s| s.swarm! if config[:swarm][:auto_swarm] }
|
155
|
+
end
|
156
|
+
|
157
|
+
# @return [Hash<Symbol,Boolean|Symbol>]
|
158
|
+
#
|
159
|
+
# @api public
|
160
|
+
# @since 1.9.0
|
161
|
+
def swarmize!
|
162
|
+
swarm.swarm!
|
163
|
+
end
|
164
|
+
|
165
|
+
# @return [Hash<Symbol,Boolean|Symbol>]
|
166
|
+
#
|
167
|
+
# @api public
|
168
|
+
# @since 1.9.0
|
169
|
+
def deswarmize!
|
170
|
+
swarm.deswarm!
|
171
|
+
end
|
172
|
+
|
173
|
+
# @option zombie_ttl [Integer]
|
174
|
+
# @return [Hash<String,Hash<Symbol,Float|Time>>]
|
175
|
+
#
|
176
|
+
# @api public
|
177
|
+
# @since 1.9.0
|
178
|
+
def swarm_info(zombie_ttl: config[:swarm][:flush_zombies][:zombie_ttl])
|
179
|
+
swarm.swarm_info(zombie_ttl:)
|
96
180
|
end
|
97
181
|
|
182
|
+
# @return [Hash<Symbol,Boolean|<Hash<Symbol,Boolean>>]
|
183
|
+
#
|
184
|
+
# @api public
|
185
|
+
# @since 1.9.0
|
186
|
+
def swarm_status
|
187
|
+
swarm.swarm_status
|
188
|
+
end
|
189
|
+
alias_method :swarm_state, :swarm_status
|
190
|
+
|
191
|
+
# @return [Hash<Symbol,Boolean|String|Float>]
|
192
|
+
#
|
193
|
+
# @api public
|
194
|
+
# @since 1.9.0
|
195
|
+
def probe_hosts
|
196
|
+
swarm.probe_hosts
|
197
|
+
end
|
198
|
+
|
199
|
+
# @option zombie_ttl [Integer]
|
200
|
+
# @option lock_scan_size [Integer]
|
201
|
+
# @option queue_scan_size [Integer]
|
202
|
+
# @return [Hash<Symbol,Boolean|Set<String>>]
|
203
|
+
#
|
204
|
+
# @api public
|
205
|
+
# @since 1.9.0
|
206
|
+
def flush_zombies(
|
207
|
+
zombie_ttl: config[:swarm][:flush_zombies][:zombie_ttl],
|
208
|
+
lock_scan_size: config[:swarm][:flush_zombies][:zombie_lock_scan_size],
|
209
|
+
queue_scan_size: config[:swarm][:flush_zombies][:zombie_queue_scan_size]
|
210
|
+
)
|
211
|
+
swarm.flush_zombies(zombie_ttl:, lock_scan_size:, queue_scan_size:)
|
212
|
+
end
|
213
|
+
|
214
|
+
# @option zombie_ttl [Integer]
|
215
|
+
# @option lock_scan_size [Integer]
|
216
|
+
# @return [Set<String>]
|
217
|
+
#
|
218
|
+
# @api public
|
219
|
+
# @since 1.9.0
|
220
|
+
def zombie_locks(
|
221
|
+
zombie_ttl: config[:swarm][:flush_zombies][:zombie_ttl],
|
222
|
+
lock_scan_size: config[:swarm][:flush_zombies][:zombie_lock_scan_size]
|
223
|
+
)
|
224
|
+
swarm.zombie_locks(zombie_ttl:, lock_scan_size:)
|
225
|
+
end
|
226
|
+
|
227
|
+
# @option zombie_ttl [Integer]
|
228
|
+
# @option lock_scan_size [Integer]
|
229
|
+
# @return [Set<String>]
|
230
|
+
#
|
231
|
+
# @api ppublic
|
232
|
+
# @since 1.9.0
|
233
|
+
def zombie_acquiers(
|
234
|
+
zombie_ttl: config[:swarm][:flush_zombies][:zombie_ttl],
|
235
|
+
lock_scan_size: config[:swarm][:flush_zombies][:zombie_lock_scan_size]
|
236
|
+
)
|
237
|
+
swarm.zombie_acquiers(zombie_ttl:, lock_scan_size:)
|
238
|
+
end
|
239
|
+
|
240
|
+
# @option zombie_ttl [Integer]
|
241
|
+
# @return [Set<String>]
|
242
|
+
#
|
243
|
+
# @api public
|
244
|
+
# @since 1.9.0
|
245
|
+
def zombie_hosts(zombie_ttl: config[:swarm][:flush_zombies][:zombie_ttl])
|
246
|
+
swarm.zombie_hosts(zombie_ttl:)
|
247
|
+
end
|
248
|
+
|
249
|
+
# @return [Hash<Symbol,Set<String>>]
|
250
|
+
# Format: {
|
251
|
+
# zombie_hosts: <Set<String>>,
|
252
|
+
# zombie_acquiers: <Set<String>>,
|
253
|
+
# zombie_locks: <Set<String>>
|
254
|
+
# }
|
255
|
+
#
|
256
|
+
# @api public
|
257
|
+
# @since 1.9.0
|
258
|
+
def zombies_info(
|
259
|
+
zombie_ttl: config[:swarm][:flush_zombies][:zombie_ttl],
|
260
|
+
lock_scan_size: config[:swarm][:flush_zombies][:zombie_ttl]
|
261
|
+
)
|
262
|
+
swarm.zombies_info(zombie_ttl:, lock_scan_size:)
|
263
|
+
end
|
264
|
+
alias_method :zombies, :zombies_info
|
265
|
+
|
98
266
|
# @param lock_name [String]
|
99
267
|
# Lock name to be obtained.
|
100
268
|
# @option ttl [Integer]
|
@@ -146,6 +314,27 @@ class RedisQueuedLocks::Client
|
|
146
314
|
# @option meta [NilClass,Hash<String|Symbol,Any>]
|
147
315
|
# - A custom metadata wich will be passed to the lock data in addition to the existing data;
|
148
316
|
# - Metadata can not contain reserved lock data keys;
|
317
|
+
# @option detailed_acq_timeout_error [Boolean]
|
318
|
+
# - When the lock acquirement try reached the acquirement time limit (:timeout option) the
|
319
|
+
# `RedisQueuedLocks::LockAcquirementTimeoutError` is raised (when `raise_errors` option
|
320
|
+
# set to `true`). The error message contains the lock key name and the timeout value).
|
321
|
+
# - <true> option adds the additional details to the error message:
|
322
|
+
# - current lock queue state (you can see which acquirer blocks your request and
|
323
|
+
# how much acquirers are in queue);
|
324
|
+
# - current lock data stored inside (for example: you can check the current acquirer and
|
325
|
+
# the lock meta state if you store some additional data there);
|
326
|
+
# - Realized as an option because of the additional lock data requires two additional Redis
|
327
|
+
# queries: (1) get the current lock from redis and (2) fetch the lock queue state;
|
328
|
+
# - These two additional Redis queries has async nature so you can receive
|
329
|
+
# inconsistent data of the lock and of the lock queue in your error emssage because:
|
330
|
+
# - required lock can be released after the error moment and before the error message build;
|
331
|
+
# - required lock can be obtained by other process after the error moment and
|
332
|
+
# before the error message build;
|
333
|
+
# - required lock queue can reach a state when the blocking acquirer start to obtain the lock
|
334
|
+
# and moved from the lock queue after the error moment and before the error message build;
|
335
|
+
# - You should consider the async nature of this error message and should use received data
|
336
|
+
# from error message correspondingly;
|
337
|
+
# - pre-configred in `config[:detailed_acq_timeout_error]`;
|
149
338
|
# @option logger [::Logger,#debug]
|
150
339
|
# - Logger object used from the configuration layer (see config[:logger]);
|
151
340
|
# - See `RedisQueuedLocks::Logging::VoidLogger` for example;
|
@@ -180,6 +369,9 @@ class RedisQueuedLocks::Client
|
|
180
369
|
# - you can provide your own log sampler with bettter algorithm that should realize
|
181
370
|
# `sampling_happened?(percent) => boolean` interface
|
182
371
|
# (see `RedisQueuedLocks::Logging::Sampler` for example);
|
372
|
+
# @option log_sample_this [Boolean]
|
373
|
+
# - marks the method that everything should be logged despite the enabled log sampling;
|
374
|
+
# - makes sense when log sampling is enabled;
|
183
375
|
# @option instr_sampling_enabled [Boolean]
|
184
376
|
# - enables <instrumentaion sampling>: only the configured percent
|
185
377
|
# of RQL cases will be instrumented;
|
@@ -198,6 +390,10 @@ class RedisQueuedLocks::Client
|
|
198
390
|
# - you can provide your own log sampler with bettter algorithm that should realize
|
199
391
|
# `sampling_happened?(percent) => boolean` interface
|
200
392
|
# (see `RedisQueuedLocks::Instrument::Sampler` for example);
|
393
|
+
# @option instr_sample_this [Boolean]
|
394
|
+
# - marks the method that everything should be instrumneted
|
395
|
+
# despite the enabled instrumentation sampling;
|
396
|
+
# - makes sense when instrumentation sampling is enabled;
|
201
397
|
# @param block [Block]
|
202
398
|
# A block of code that should be executed after the successfully acquired lock.
|
203
399
|
# @return [RedisQueuedLocks::Data,Hash<Symbol,Any>,yield]
|
@@ -206,7 +402,7 @@ class RedisQueuedLocks::Client
|
|
206
402
|
#
|
207
403
|
# @api public
|
208
404
|
# @since 1.0.0
|
209
|
-
# @version 1.
|
405
|
+
# @version 1.8.0
|
210
406
|
# rubocop:disable Metrics/MethodLength
|
211
407
|
def lock(
|
212
408
|
lock_name,
|
@@ -223,6 +419,7 @@ class RedisQueuedLocks::Client
|
|
223
419
|
access_strategy: config[:default_access_strategy],
|
224
420
|
identity: uniq_identity,
|
225
421
|
meta: nil,
|
422
|
+
detailed_acq_timeout_error: config[:detailed_acq_timeout_error],
|
226
423
|
logger: config[:logger],
|
227
424
|
log_lock_try: config[:log_lock_try],
|
228
425
|
instrumenter: config[:instrumenter],
|
@@ -230,9 +427,11 @@ class RedisQueuedLocks::Client
|
|
230
427
|
log_sampling_enabled: config[:log_sampling_enabled],
|
231
428
|
log_sampling_percent: config[:log_sampling_percent],
|
232
429
|
log_sampler: config[:log_sampler],
|
430
|
+
log_sample_this: false,
|
233
431
|
instr_sampling_enabled: config[:instr_sampling_enabled],
|
234
432
|
instr_sampling_percent: config[:instr_sampling_percent],
|
235
433
|
instr_sampler: config[:instr_sampler],
|
434
|
+
instr_sample_this: false,
|
236
435
|
&block
|
237
436
|
)
|
238
437
|
RedisQueuedLocks::Acquier::AcquireLock.acquire_lock(
|
@@ -256,15 +455,18 @@ class RedisQueuedLocks::Client
|
|
256
455
|
conflict_strategy:,
|
257
456
|
access_strategy:,
|
258
457
|
meta:,
|
458
|
+
detailed_acq_timeout_error:,
|
259
459
|
logger:,
|
260
460
|
log_lock_try:,
|
261
461
|
instrument:,
|
262
462
|
log_sampling_enabled:,
|
263
463
|
log_sampling_percent:,
|
264
464
|
log_sampler:,
|
465
|
+
log_sample_this:,
|
265
466
|
instr_sampling_enabled:,
|
266
467
|
instr_sampling_percent:,
|
267
468
|
instr_sampler:,
|
469
|
+
instr_sample_this:,
|
268
470
|
&block
|
269
471
|
)
|
270
472
|
end
|
@@ -274,7 +476,7 @@ class RedisQueuedLocks::Client
|
|
274
476
|
#
|
275
477
|
# @api public
|
276
478
|
# @since 1.0.0
|
277
|
-
# @version 1.
|
479
|
+
# @version 1.8.0
|
278
480
|
# rubocop:disable Metrics/MethodLength
|
279
481
|
def lock!(
|
280
482
|
lock_name,
|
@@ -291,15 +493,18 @@ class RedisQueuedLocks::Client
|
|
291
493
|
identity: uniq_identity,
|
292
494
|
instrumenter: config[:instrumenter],
|
293
495
|
meta: nil,
|
496
|
+
detailed_acq_timeout_error: config[:detailed_acq_timeout_error],
|
294
497
|
logger: config[:logger],
|
295
498
|
log_lock_try: config[:log_lock_try],
|
296
499
|
instrument: nil,
|
297
500
|
log_sampling_enabled: config[:log_sampling_enabled],
|
298
501
|
log_sampling_percent: config[:log_sampling_percent],
|
299
502
|
log_sampler: config[:log_sampler],
|
503
|
+
log_sample_this: false,
|
300
504
|
instr_sampling_enabled: config[:instr_sampling_enabled],
|
301
505
|
instr_sampling_percent: config[:instr_sampling_percent],
|
302
506
|
instr_sampler: config[:instr_sampler],
|
507
|
+
instr_sample_this: false,
|
303
508
|
&block
|
304
509
|
)
|
305
510
|
lock(
|
@@ -317,6 +522,7 @@ class RedisQueuedLocks::Client
|
|
317
522
|
logger:,
|
318
523
|
log_lock_try:,
|
319
524
|
meta:,
|
525
|
+
detailed_acq_timeout_error:,
|
320
526
|
instrument:,
|
321
527
|
instrumenter:,
|
322
528
|
conflict_strategy:,
|
@@ -324,9 +530,11 @@ class RedisQueuedLocks::Client
|
|
324
530
|
log_sampling_enabled:,
|
325
531
|
log_sampling_percent:,
|
326
532
|
log_sampler:,
|
533
|
+
log_sample_this:,
|
327
534
|
instr_sampling_enabled:,
|
328
535
|
instr_sampling_percent:,
|
329
536
|
instr_sampler:,
|
537
|
+
instr_sample_this:,
|
330
538
|
&block
|
331
539
|
)
|
332
540
|
end
|
@@ -339,9 +547,11 @@ class RedisQueuedLocks::Client
|
|
339
547
|
# @option log_sampling_enabled [Boolean]
|
340
548
|
# @option log_sampling_percent [Integer]
|
341
549
|
# @option log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
550
|
+
# @option log_sample_this [Boolean]
|
342
551
|
# @option instr_sampling_enabled [Boolean]
|
343
552
|
# @option instr_sampling_percent [Integer]
|
344
553
|
# @option instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
554
|
+
# @option instr_sample_this [Boolean]
|
345
555
|
# @return [RedisQueuedLocks::Data, Hash<Symbol,Any>]
|
346
556
|
# Format: {
|
347
557
|
# ok: true/false,
|
@@ -365,9 +575,11 @@ class RedisQueuedLocks::Client
|
|
365
575
|
log_sampling_enabled: config[:log_sampling_enabled],
|
366
576
|
log_sampling_percent: config[:log_sampling_percent],
|
367
577
|
log_sampler: config[:log_sampler],
|
578
|
+
log_sample_this: false,
|
368
579
|
instr_sampling_enabled: config[:instr_sampling_enabled],
|
369
580
|
instr_sampling_percent: config[:instr_sampling_percent],
|
370
|
-
instr_sampler: config[:instr_sampler]
|
581
|
+
instr_sampler: config[:instr_sampler],
|
582
|
+
instr_sample_this: false
|
371
583
|
)
|
372
584
|
RedisQueuedLocks::Acquier::ReleaseLock.release_lock(
|
373
585
|
redis_client,
|
@@ -377,11 +589,14 @@ class RedisQueuedLocks::Client
|
|
377
589
|
log_sampling_enabled,
|
378
590
|
log_sampling_percent,
|
379
591
|
log_sampler,
|
592
|
+
log_sample_this,
|
380
593
|
instr_sampling_enabled,
|
381
594
|
instr_sampling_percent,
|
382
|
-
instr_sampler
|
595
|
+
instr_sampler,
|
596
|
+
instr_sample_this
|
383
597
|
)
|
384
598
|
end
|
599
|
+
alias_method :release_lock, :unlock
|
385
600
|
|
386
601
|
# @param lock_name [String]
|
387
602
|
# @return [Boolean]
|
@@ -419,6 +634,82 @@ class RedisQueuedLocks::Client
|
|
419
634
|
RedisQueuedLocks::Acquier::QueueInfo.queue_info(redis_client, lock_name)
|
420
635
|
end
|
421
636
|
|
637
|
+
# Retrun the current acquirer identifier.
|
638
|
+
#
|
639
|
+
# @option process_id [Integer,Any] Process identifier.
|
640
|
+
# @option thread_id [Integer,Any] Thread identifier.
|
641
|
+
# @option fiber_id [Integer,Any] Fiber identifier.
|
642
|
+
# @option ractor_id [Integer,Any] Ractor identifier.
|
643
|
+
# @option identity [String] Unique per-process string. See `config[:uniq_identifier]`.
|
644
|
+
# @return [String]
|
645
|
+
#
|
646
|
+
# @see RedisQueuedLocks::Resource.acquier_identifier
|
647
|
+
# @see RedisQueuedLocks::Resource.get_process_id
|
648
|
+
# @see RedisQueuedLocks::Resource.get_thread_id
|
649
|
+
# @see RedisQueuedLocks::Resource.get_fiber_id
|
650
|
+
# @see RedisQueuedLocks::Resource.get_ractor_id
|
651
|
+
# @see RedisQueuedLocks::Client#uniq_identity
|
652
|
+
#
|
653
|
+
# @api public
|
654
|
+
# @since 1.8.0
|
655
|
+
def current_acquier_id(
|
656
|
+
process_id: RedisQueuedLocks::Resource.get_process_id,
|
657
|
+
thread_id: RedisQueuedLocks::Resource.get_thread_id,
|
658
|
+
fiber_id: RedisQueuedLocks::Resource.get_fiber_id,
|
659
|
+
ractor_id: RedisQueuedLocks::Resource.get_ractor_id,
|
660
|
+
identity: uniq_identity
|
661
|
+
)
|
662
|
+
RedisQueuedLocks::Resource.acquier_identifier(
|
663
|
+
process_id,
|
664
|
+
thread_id,
|
665
|
+
fiber_id,
|
666
|
+
ractor_id,
|
667
|
+
identity
|
668
|
+
)
|
669
|
+
end
|
670
|
+
|
671
|
+
# Retrun the current host identifier.
|
672
|
+
#
|
673
|
+
# @option process_id [Integer,Any] Process identifier.
|
674
|
+
# @option thread_id [Integer,Any] Thread identifier.
|
675
|
+
# @option fiber_id [Integer,Any] Fiber identifier.
|
676
|
+
# @option ractor_id [Integer,Any] Ractor identifier.
|
677
|
+
# @option identity [String] Unique per-process string. See `config[:uniq_identifier]`.
|
678
|
+
# @return [String]
|
679
|
+
#
|
680
|
+
# @see RedisQueuedLocks::Resource.host_identifier
|
681
|
+
# @see RedisQueuedLocks::Resource.get_process_id
|
682
|
+
# @see RedisQueuedLocks::Resource.get_thread_id
|
683
|
+
# @see RedisQueuedLocks::Resource.get_ractor_id
|
684
|
+
# @see RedisQueuedLocks::Client#uniq_identity
|
685
|
+
#
|
686
|
+
# @api public
|
687
|
+
# @since 1.9.0
|
688
|
+
def current_host_id(
|
689
|
+
process_id: RedisQueuedLocks::Resource.get_process_id,
|
690
|
+
thread_id: RedisQueuedLocks::Resource.get_thread_id,
|
691
|
+
ractor_id: RedisQueuedLocks::Resource.get_ractor_id,
|
692
|
+
identity: uniq_identity
|
693
|
+
)
|
694
|
+
RedisQueuedLocks::Resource.host_identifier(
|
695
|
+
process_id,
|
696
|
+
thread_id,
|
697
|
+
ractor_id,
|
698
|
+
identity
|
699
|
+
)
|
700
|
+
end
|
701
|
+
|
702
|
+
# Return the list of possible host identifiers that can be reached from the current ractor.
|
703
|
+
#
|
704
|
+
# @param identity [String] Unique identity (RedisQueuedLocks::Client#uniq_identity by default)
|
705
|
+
# @return [Array<String>]
|
706
|
+
#
|
707
|
+
# @api public
|
708
|
+
# @since 1.9.0
|
709
|
+
def possible_host_ids(identity = uniq_identity)
|
710
|
+
RedisQueuedLocks::Resource.possible_host_identifiers(identity)
|
711
|
+
end
|
712
|
+
|
422
713
|
# This method is non-atomic cuz redis does not provide an atomic function for TTL/PTTL extension.
|
423
714
|
# So the methid is spliited into the two commands:
|
424
715
|
# (1) read current pttl
|
@@ -438,9 +729,11 @@ class RedisQueuedLocks::Client
|
|
438
729
|
# @option log_sampling_enabled [Boolean]
|
439
730
|
# @option log_sampling_percent [Integer]
|
440
731
|
# @option log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
732
|
+
# @option log_sample_this [Boolean]
|
441
733
|
# @option instr_sampling_enabled [Boolean]
|
442
734
|
# @option instr_sampling_percent [Integer]
|
443
735
|
# @option instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
736
|
+
# @option instr_sample_this [Boolean]
|
444
737
|
# @return [Hash<Symbol,Boolean|Symbol>]
|
445
738
|
# - { ok: true, result: :ttl_extended }
|
446
739
|
# - { ok: false, result: :async_expire_or_no_lock }
|
@@ -457,9 +750,11 @@ class RedisQueuedLocks::Client
|
|
457
750
|
log_sampling_enabled: config[:log_sampling_enabled],
|
458
751
|
log_sampling_percent: config[:log_sampling_percent],
|
459
752
|
log_sampler: config[:log_sampler],
|
753
|
+
log_sample_this: false,
|
460
754
|
instr_sampling_enabled: config[:instr_sampling_enabled],
|
461
755
|
instr_sampling_percent: config[:instr_sampling_percent],
|
462
|
-
instr_sampler: config[:instr_sampler]
|
756
|
+
instr_sampler: config[:instr_sampler],
|
757
|
+
instr_sample_this: false
|
463
758
|
)
|
464
759
|
RedisQueuedLocks::Acquier::ExtendLockTTL.extend_lock_ttl(
|
465
760
|
redis_client,
|
@@ -471,9 +766,11 @@ class RedisQueuedLocks::Client
|
|
471
766
|
log_sampling_enabled,
|
472
767
|
log_sampling_percent,
|
473
768
|
log_sampler,
|
769
|
+
log_sample_this,
|
474
770
|
instr_sampling_enabled,
|
475
771
|
instr_sampling_percent,
|
476
|
-
instr_sampler
|
772
|
+
instr_sampler,
|
773
|
+
instr_sample_this
|
477
774
|
)
|
478
775
|
end
|
479
776
|
|
@@ -489,9 +786,11 @@ class RedisQueuedLocks::Client
|
|
489
786
|
# @option log_sampling_enabled [Boolean]
|
490
787
|
# @option log_sampling_percent [Integer]
|
491
788
|
# @option log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
789
|
+
# @option log_sample_this [Boolean]
|
492
790
|
# @option instr_sampling_enabled [Boolean]
|
493
791
|
# @option instr_sampling_percent [Integer]
|
494
792
|
# @option instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
793
|
+
# @option instr_sample_this [Boolean]
|
495
794
|
# @return [RedisQueuedLocks::Data,Hash<Symbol,Boolean|Hash<Symbol,Numeric>>]
|
496
795
|
# Example: { ok: true, result { rel_key_cnt: 100, rel_time: 0.01 } }
|
497
796
|
#
|
@@ -506,9 +805,11 @@ class RedisQueuedLocks::Client
|
|
506
805
|
log_sampling_enabled: config[:log_sampling_enabled],
|
507
806
|
log_sampling_percent: config[:log_sampling_percent],
|
508
807
|
log_sampler: config[:log_sampler],
|
808
|
+
log_sample_this: false,
|
509
809
|
instr_sampling_enabled: config[:instr_sampling_enabled],
|
510
810
|
instr_sampling_percent: config[:instr_sampling_percent],
|
511
|
-
instr_sampler: config[:instr_sampler]
|
811
|
+
instr_sampler: config[:instr_sampler],
|
812
|
+
instr_sample_this: false
|
512
813
|
)
|
513
814
|
RedisQueuedLocks::Acquier::ReleaseAllLocks.release_all_locks(
|
514
815
|
redis_client,
|
@@ -519,11 +820,14 @@ class RedisQueuedLocks::Client
|
|
519
820
|
log_sampling_enabled,
|
520
821
|
log_sampling_percent,
|
521
822
|
log_sampler,
|
823
|
+
log_sample_this,
|
522
824
|
instr_sampling_enabled,
|
523
825
|
instr_sampling_percent,
|
524
|
-
instr_sampler
|
826
|
+
instr_sampler,
|
827
|
+
instr_sample_this
|
525
828
|
)
|
526
829
|
end
|
830
|
+
alias_method :release_locks, :clear_locks
|
527
831
|
|
528
832
|
# @option scan_size [Integer]
|
529
833
|
# The batch of scanned keys for Redis'es SCAN command.
|
@@ -612,9 +916,11 @@ class RedisQueuedLocks::Client
|
|
612
916
|
# @option log_sampling_enabled [Boolean]
|
613
917
|
# @option log_sampling_percent [Integer]
|
614
918
|
# @option log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
919
|
+
# @option log_sample_this [Boolean]
|
615
920
|
# @option instr_sampling_enabled [Boolean]
|
616
921
|
# @option instr_sampling_percent [Integer]
|
617
922
|
# @option instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
923
|
+
# @option instr_sample_this [Boolean]
|
618
924
|
# @return [Hash<Symbol,Boolean|Hash<Symbol,Set<String>>>]
|
619
925
|
# Format: { ok: true, result: { processed_queus: Set<String> } }
|
620
926
|
#
|
@@ -630,9 +936,11 @@ class RedisQueuedLocks::Client
|
|
630
936
|
log_sampling_enabled: config[:log_sampling_enabled],
|
631
937
|
log_sampling_percent: config[:log_sampling_percent],
|
632
938
|
log_sampler: config[:log_sampler],
|
939
|
+
log_sample_this: false,
|
633
940
|
instr_sampling_enabled: config[:instr_sampling_enabled],
|
634
941
|
instr_sampling_percent: config[:instr_sampling_percent],
|
635
|
-
instr_sampler: config[:instr_sampler]
|
942
|
+
instr_sampler: config[:instr_sampler],
|
943
|
+
instr_sample_this: false
|
636
944
|
)
|
637
945
|
RedisQueuedLocks::Acquier::ClearDeadRequests.clear_dead_requests(
|
638
946
|
redis_client,
|
@@ -644,9 +952,11 @@ class RedisQueuedLocks::Client
|
|
644
952
|
log_sampling_enabled,
|
645
953
|
log_sampling_percent,
|
646
954
|
log_sampler,
|
955
|
+
log_sample_this,
|
647
956
|
instr_sampling_enabled,
|
648
957
|
instr_sampling_percent,
|
649
|
-
instr_sampler
|
958
|
+
instr_sampler,
|
959
|
+
instr_sample_this
|
650
960
|
)
|
651
961
|
end
|
652
962
|
end
|
@@ -28,4 +28,12 @@ module RedisQueuedLocks
|
|
28
28
|
# @api public
|
29
29
|
# @since 1.3.0
|
30
30
|
ConflictLockObtainError = Class.new(Error)
|
31
|
+
|
32
|
+
# @api public
|
33
|
+
# @since 1.9.0
|
34
|
+
SwarmError = Class.new(Error)
|
35
|
+
|
36
|
+
# @api public
|
37
|
+
# @since 1.9.0
|
38
|
+
SwarmArgumentError = Class.new(ArgumentError)
|
31
39
|
end
|
@@ -10,14 +10,21 @@ module RedisQueuedLocks::Instrument
|
|
10
10
|
|
11
11
|
class << self
|
12
12
|
# @param instr_sampling_enabled [Boolean]
|
13
|
+
# @param instr_sample_this [Boolean]
|
13
14
|
# @param instr_sampling_percent [Integer]
|
14
15
|
# @param instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
15
16
|
# @return [Boolean]
|
16
17
|
#
|
17
18
|
# @api private
|
18
19
|
# @since 1.6.0
|
19
|
-
def should_instrument?(
|
20
|
+
def should_instrument?(
|
21
|
+
instr_sampling_enabled,
|
22
|
+
instr_sample_this,
|
23
|
+
instr_sampling_percent,
|
24
|
+
instr_sampler
|
25
|
+
)
|
20
26
|
return true unless instr_sampling_enabled
|
27
|
+
return true if instr_sample_this
|
21
28
|
instr_sampler.sampling_happened?(instr_sampling_percent)
|
22
29
|
end
|
23
30
|
|
@@ -9,14 +9,21 @@ module RedisQueuedLocks::Logging
|
|
9
9
|
|
10
10
|
class << self
|
11
11
|
# @param log_sampling_enabled [Boolean]
|
12
|
+
# @param log_sample_this [Boolean]
|
12
13
|
# @param log_sampling_percent [Integer]
|
13
14
|
# @param log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
14
15
|
# @return [Boolean]
|
15
16
|
#
|
16
17
|
# @api private
|
17
18
|
# @since 1.5.0
|
18
|
-
def should_log?(
|
19
|
+
def should_log?(
|
20
|
+
log_sampling_enabled,
|
21
|
+
log_sample_this,
|
22
|
+
log_sampling_percent,
|
23
|
+
log_sampler
|
24
|
+
)
|
19
25
|
return true unless log_sampling_enabled
|
26
|
+
return true if log_sample_this
|
20
27
|
log_sampler.sampling_happened?(log_sampling_percent)
|
21
28
|
end
|
22
29
|
|