redis_queued_locks 1.6.0 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.0.0
25
- extend RedisQueuedLocks::Utilities
28
+ # @since 1.7.0
29
+ extend DequeueFromLockQueue
26
30
 
27
31
  class << self
28
32
  # @param redis [RedisClient]
@@ -65,6 +69,10 @@ module RedisQueuedLocks::Acquier::AcquireLock
65
69
  # @option meta [NilClass,Hash<String|Symbol,Any>]
66
70
  # - A custom metadata wich will be passed to the lock data in addition to the existing data;
67
71
  # - Metadata can not contain reserved lock data keys;
72
+ # @option detailed_acq_timeout_error [Boolean]
73
+ # - Add additional data to the acquirement timeout error such as the current lock queue state
74
+ # and the required lock state;
75
+ # - See `config[:detailed_acq_timeout_error]` for details;
68
76
  # @option logger [::Logger,#debug]
69
77
  # - Logger object used from the configuration layer (see config[:logger]);
70
78
  # - See `RedisQueuedLocks::Logging::VoidLogger` for example;
@@ -86,6 +94,16 @@ module RedisQueuedLocks::Acquier::AcquireLock
86
94
  # - `:extendable_work_through`;
87
95
  # - `:wait_for_lock`;
88
96
  # - `:dead_locking`;
97
+ # @option access_strategy [Symbol]
98
+ # - The way in which the lock will be obtained;
99
+ # - By default it uses `:queued` strategy;
100
+ # - Supports following strategies:
101
+ # - `:queued` (FIFO): the classic queued behavior (default), your lock will be
102
+ # obitaned if you are first in queue and the required lock is free;
103
+ # - `:random` (RANDOM): obtain a lock without checking the positions in the queue
104
+ # (but with checking the limist, retries, timeouts and so on). if lock is
105
+ # free to obtain - it will be obtained;
106
+ # - pre-configured in `config[:default_access_strategy]`;
89
107
  # @option log_sampling_enabled [Boolean]
90
108
  # - enables <log sampling>: only the configured percent of RQL cases will be logged;
91
109
  # - disabled by default;
@@ -129,7 +147,7 @@ module RedisQueuedLocks::Acquier::AcquireLock
129
147
  #
130
148
  # @api private
131
149
  # @since 1.0.0
132
- # @version 1.6.0
150
+ # @version 1.8.0
133
151
  def acquire_lock(
134
152
  redis,
135
153
  lock_name,
@@ -149,10 +167,12 @@ module RedisQueuedLocks::Acquier::AcquireLock
149
167
  identity:,
150
168
  fail_fast:,
151
169
  meta:,
170
+ detailed_acq_timeout_error:,
152
171
  instrument:,
153
172
  logger:,
154
173
  log_lock_try:,
155
174
  conflict_strategy:,
175
+ access_strategy:,
156
176
  log_sampling_enabled:,
157
177
  log_sampling_percent:,
158
178
  log_sampler:,
@@ -231,53 +251,52 @@ module RedisQueuedLocks::Acquier::AcquireLock
231
251
 
232
252
  acq_dequeue = proc do
233
253
  dequeue_from_lock_queue(
234
- redis, logger,
254
+ redis,
255
+ logger,
235
256
  lock_key,
236
257
  lock_key_queue,
237
258
  queue_ttl,
238
259
  acquier_id,
260
+ access_strategy,
239
261
  log_sampled,
240
262
  instr_sampled
241
263
  )
242
264
  end
243
265
 
244
- run_non_critical do
245
- logger.debug do
246
- "[redis_queued_locks.start_lock_obtaining] " \
247
- "lock_key => '#{lock_key}' " \
248
- "queue_ttl => #{queue_ttl} " \
249
- "acq_id => '#{acquier_id}'"
250
- end
251
- end if log_sampled
266
+ LogVisitor.start_lock_obtaining(
267
+ logger, log_sampled,
268
+ lock_key, queue_ttl, acquier_id, access_strategy
269
+ )
252
270
 
253
271
  # Step 2: try to lock with timeout
254
- with_acq_timeout(timeout, lock_key, raise_errors, on_timeout: acq_dequeue) do
272
+ with_acq_timeout(
273
+ redis,
274
+ timeout,
275
+ lock_key,
276
+ lock_name,
277
+ raise_errors,
278
+ detailed_acq_timeout_error,
279
+ on_timeout: acq_dequeue
280
+ ) do
255
281
  acq_start_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond)
256
282
 
257
283
  # Step 2.1: cyclically try to obtain the lock
258
284
  while acq_process[:should_try]
259
- run_non_critical do
260
- logger.debug do
261
- "[redis_queued_locks.start_try_to_lock_cycle] " \
262
- "lock_key => '#{lock_key}' " \
263
- "queue_ttl => #{queue_ttl} " \
264
- "acq_id => '{#{acquier_id}'"
265
- end
266
- end if log_sampled
285
+
286
+ LogVisitor.start_try_to_lock_cycle(
287
+ logger, log_sampled,
288
+ lock_key, queue_ttl, acquier_id, access_strategy
289
+ )
267
290
 
268
291
  # Step 2.X: check the actual score: is it in queue ttl limit or not?
269
292
  if RedisQueuedLocks::Resource.dead_score_reached?(acquier_position, queue_ttl)
270
293
  # Step 2.X.X: dead score reached => re-queue the lock request with the new score;
271
294
  acquier_position = RedisQueuedLocks::Resource.calc_initial_acquier_position
272
295
 
273
- run_non_critical do
274
- logger.debug do
275
- "[redis_queued_locks.dead_score_reached__reset_acquier_position] " \
276
- "lock_key => '#{lock_key} " \
277
- "queue_ttl => #{queue_ttl} " \
278
- "acq_id => '#{acquier_id}'"
279
- end
280
- end if log_sampled
296
+ LogVisitor.dead_score_reached__reset_acquier_position(
297
+ logger, log_sampled,
298
+ lock_key, queue_ttl, acquier_id, access_strategy
299
+ )
281
300
  end
282
301
 
283
302
  try_to_lock(
@@ -292,6 +311,7 @@ module RedisQueuedLocks::Acquier::AcquireLock
292
311
  queue_ttl,
293
312
  fail_fast,
294
313
  conflict_strategy,
314
+ access_strategy,
295
315
  meta,
296
316
  log_sampled,
297
317
  instr_sampled
@@ -309,72 +329,38 @@ module RedisQueuedLocks::Acquier::AcquireLock
309
329
  # Step X: (instrumentation)
310
330
  if acq_process[:result][:process] == :extendable_conflict_work_through
311
331
  # instrumetnation: (reentrant lock with ttl extension)
312
- run_non_critical do
313
- logger.debug do
314
- "[redis_queued_locks.extendable_reentrant_lock_obtained] " \
315
- "lock_key => '#{result[:lock_key]}' " \
316
- "queue_ttl => #{queue_ttl} " \
317
- "acq_id => '#{acquier_id}' " \
318
- "acq_time => #{acq_time} (ms)"
319
- end
320
- end if log_sampled
321
-
322
- run_non_critical do
323
- instrumenter.notify('redis_queued_locks.extendable_reentrant_lock_obtained', {
324
- lock_key: result[:lock_key],
325
- ttl: result[:ttl],
326
- acq_id: result[:acq_id],
327
- ts: result[:ts],
328
- acq_time: acq_time,
329
- instrument:
330
- })
331
- end if instr_sampled
332
+ LogVisitor.extendable_reentrant_lock_obtained(
333
+ logger, log_sampled,
334
+ result[:lock_key], queue_ttl, acquier_id, acq_time, access_strategy
335
+ )
336
+ InstrVisitor.extendable_reentrant_lock_obtained(
337
+ instrumenter, instr_sampled,
338
+ result[:lock_key], result[:ttl], result[:acq_id], result[:ts], acq_time,
339
+ instrument
340
+ )
332
341
  elsif acq_process[:result][:process] == :conflict_work_through
333
342
  # instrumetnation: (reentrant lock without ttl extension)
334
- run_non_critical do
335
- logger.debug do
336
- "[redis_queued_locks.reentrant_lock_obtained] " \
337
- "lock_key => '#{result[:lock_key]}' " \
338
- "queue_ttl => #{queue_ttl} " \
339
- "acq_id => '#{acquier_id}' " \
340
- "acq_time => #{acq_time} (ms)"
341
- end
342
- end if log_sampled
343
-
344
- run_non_critical do
345
- instrumenter.notify('redis_queued_locks.reentrant_lock_obtained', {
346
- lock_key: result[:lock_key],
347
- ttl: result[:ttl],
348
- acq_id: result[:acq_id],
349
- ts: result[:ts],
350
- acq_time: acq_time,
351
- instrument:
352
- })
353
- end if instr_sampled
343
+ LogVisitor.reentrant_lock_obtained(
344
+ logger, log_sampled,
345
+ result[:lock_key], queue_ttl, acquier_id, acq_time, access_strategy
346
+ )
347
+ InstrVisitor.reentrant_lock_obtained(
348
+ instrumenter, instr_sampled,
349
+ result[:lock_key], result[:ttl], result[:acq_id], result[:ts], acq_time,
350
+ instrument
351
+ )
354
352
  else
355
353
  # instrumentation: (classic lock obtain)
356
354
  # NOTE: classic is: acq_process[:result][:process] == :lock_obtaining
357
- run_non_critical do
358
- logger.debug do
359
- "[redis_queued_locks.lock_obtained] " \
360
- "lock_key => '#{result[:lock_key]}' " \
361
- "queue_ttl => #{queue_ttl} " \
362
- "acq_id => '#{acquier_id}' " \
363
- "acq_time => #{acq_time} (ms)"
364
- end
365
- end if log_sampled
366
-
367
- # Step X (instrumentation): lock obtained
368
- run_non_critical do
369
- instrumenter.notify('redis_queued_locks.lock_obtained', {
370
- lock_key: result[:lock_key],
371
- ttl: result[:ttl],
372
- acq_id: result[:acq_id],
373
- ts: result[:ts],
374
- acq_time: acq_time,
375
- instrument:
376
- })
377
- end if instr_sampled
355
+ LogVisitor.lock_obtained(
356
+ logger, log_sampled,
357
+ result[:lock_key], queue_ttl, acquier_id, acq_time, access_strategy
358
+ )
359
+ InstrVisitor.lock_obtained(
360
+ instrumenter, instr_sampled,
361
+ result[:lock_key], result[:ttl], result[:acq_id], result[:ts], acq_time,
362
+ instrument
363
+ )
378
364
  end
379
365
 
380
366
  # Step 2.1.a: successfully acquired => build the result
@@ -478,10 +464,12 @@ module RedisQueuedLocks::Acquier::AcquireLock
478
464
  logger,
479
465
  lock_key,
480
466
  acquier_id,
467
+ access_strategy,
481
468
  timed,
482
469
  ttl_shift,
483
470
  ttl,
484
471
  queue_ttl,
472
+ meta,
485
473
  log_sampled,
486
474
  instr_sampled,
487
475
  should_expire, # NOTE: should expire the lock after the block execution
@@ -499,30 +487,30 @@ module RedisQueuedLocks::Acquier::AcquireLock
499
487
  if acq_process[:result][:process] == :extendable_conflict_work_through ||
500
488
  acq_process[:result][:process] == :conflict_work_through
501
489
  # Step X (instrumentation): reentrant_lock_hold_completes
502
- run_non_critical do
503
- instrumenter.notify('redis_queued_locks.reentrant_lock_hold_completes', {
504
- hold_time: acq_process[:hold_time],
505
- ttl: acq_process[:lock_info][:ttl],
506
- acq_id: acq_process[:lock_info][:acq_id],
507
- ts: acq_process[:lock_info][:ts],
508
- lock_key: acq_process[:lock_info][:lock_key],
509
- acq_time: acq_process[:acq_time],
510
- instrument:
511
- })
512
- end if instr_sampled
490
+ InstrVisitor.reentrant_lock_hold_completes(
491
+ instrumenter,
492
+ instr_sampled,
493
+ acq_process[:lock_info][:lock_key],
494
+ acq_process[:lock_info][:ttl],
495
+ acq_process[:lock_info][:acq_id],
496
+ acq_process[:lock_info][:ts],
497
+ acq_process[:acq_time],
498
+ acq_process[:hold_time],
499
+ instrument
500
+ )
513
501
  else
514
502
  # Step X (instrumentation): lock_hold_and_release
515
- run_non_critical do
516
- instrumenter.notify('redis_queued_locks.lock_hold_and_release', {
517
- hold_time: acq_process[:hold_time],
518
- ttl: acq_process[:lock_info][:ttl],
519
- acq_id: acq_process[:lock_info][:acq_id],
520
- ts: acq_process[:lock_info][:ts],
521
- lock_key: acq_process[:lock_info][:lock_key],
522
- acq_time: acq_process[:acq_time],
523
- instrument:
524
- })
525
- end if instr_sampled
503
+ InstrVisitor.lock_hold_and_release(
504
+ instrumenter,
505
+ instr_sampled,
506
+ acq_process[:lock_info][:lock_key],
507
+ acq_process[:lock_info][:ttl],
508
+ acq_process[:lock_info][:acq_id],
509
+ acq_process[:lock_info][:ts],
510
+ acq_process[:lock_info][:lock_key],
511
+ acq_process[:acq_time],
512
+ instrument
513
+ )
526
514
  end
527
515
  end
528
516
  else
@@ -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
@@ -23,6 +24,7 @@ class RedisQueuedLocks::Client
23
24
  setting :dead_request_ttl, (1 * 24 * 60 * 60 * 1000) # NOTE: 1 day in milliseconds
24
25
  setting :is_timed_by_default, false
25
26
  setting :default_conflict_strategy, :wait_for_lock
27
+ setting :default_access_strategy, :queued
26
28
  setting :log_sampling_enabled, false
27
29
  setting :log_sampling_percent, 15
28
30
  setting :log_sampler, RedisQueuedLocks::Logging::Sampler
@@ -36,6 +38,7 @@ class RedisQueuedLocks::Client
36
38
  validate('try_to_lock_timeout') { |val| val == nil || (val.is_a?(::Integer) && val >= 0) }
37
39
  validate('default_lock_tt', :integer)
38
40
  validate('default_queue_ttl', :integer)
41
+ validate('detailed_acq_timeout_error', :boolean)
39
42
  validate('lock_release_batch_size', :integer)
40
43
  validate('instrumenter') { |val| RedisQueuedLocks::Instrument.valid_interface?(val) }
41
44
  validate('uniq_identifier', :proc)
@@ -57,6 +60,12 @@ class RedisQueuedLocks::Client
57
60
  val == :dead_locking
58
61
  # rubocop:enable Layout/MultilineOperationIndentation
59
62
  end
63
+ validate('default_access_strategy') do |val|
64
+ # rubocop:disable Layout/MultilineOperationIndentation
65
+ val == :queued ||
66
+ val == :random
67
+ # rubocop:enable Layout/MultilineOperationIndentation
68
+ end
60
69
  end
61
70
 
62
71
  # @return [RedisClient]
@@ -88,6 +97,39 @@ class RedisQueuedLocks::Client
88
97
  @redis_client = redis_client
89
98
  end
90
99
 
100
+ # Retrun the current acquirer identifier.
101
+ #
102
+ # @option process_id [Integer,Any] Process identifier.
103
+ # @option thread_id [Integer,Any] Thread identifier.
104
+ # @option fiber_id [Integer,Any] Fiber identifier.
105
+ # @option ractor_id [Integer,Any] Ractor identifier.
106
+ # @option identity [String] Unique per-process string. See `config[:uniq_identifier]`.
107
+ # @return [String]
108
+ #
109
+ # @see RedisQueuedLocks::Resource.get_process_id
110
+ # @see RedisQueuedLocks::Resource.get_thread_id
111
+ # @see RedisQueuedLocks::Resource.get_fiber_id
112
+ # @see RedisQueuedLocks::Resource.get_ractor_id
113
+ # @see RedisQueuedLocks::Client#uniq_identity
114
+ #
115
+ # @api public
116
+ # @since 1.8.0
117
+ def current_acquier_id(
118
+ process_id: RedisQueuedLocks::Resource.get_process_id,
119
+ thread_id: RedisQueuedLocks::Resource.get_thread_id,
120
+ fiber_id: RedisQueuedLocks::Resource.get_fiber_id,
121
+ ractor_id: RedisQueuedLocks::Resource.get_ractor_id,
122
+ identity: uniq_identity
123
+ )
124
+ RedisQueuedLocks::Resource.acquier_identifier(
125
+ process_id,
126
+ thread_id,
127
+ fiber_id,
128
+ ractor_id,
129
+ identity
130
+ )
131
+ end
132
+
91
133
  # @param lock_name [String]
92
134
  # Lock name to be obtained.
93
135
  # @option ttl [Integer]
@@ -126,9 +168,40 @@ class RedisQueuedLocks::Client
126
168
  # - `:wait_for_lock` - (default) - work in classic way
127
169
  # (with timeouts, retry delays, retry limits, etc - in classic way :));
128
170
  # - `:dead_locking` - fail with deadlock exception;
171
+ # @option access_strategy [Symbol]
172
+ # - The way in which the lock will be obtained;
173
+ # - By default it uses `:queued` strategy;
174
+ # - Supports following strategies:
175
+ # - `:queued` (FIFO): the classic queued behavior (default), your lock will be
176
+ # obitaned if you are first in queue and the required lock is free;
177
+ # - `:random` (RANDOM): obtain a lock without checking the positions in the queue
178
+ # (but with checking the limist, retries, timeouts and so on). if lock is
179
+ # free to obtain - it will be obtained;
180
+ # - pre-configured in `config[:default_access_strategy]`;
129
181
  # @option meta [NilClass,Hash<String|Symbol,Any>]
130
182
  # - A custom metadata wich will be passed to the lock data in addition to the existing data;
131
183
  # - Metadata can not contain reserved lock data keys;
184
+ # @option detailed_acq_timeout_error [Boolean]
185
+ # - When the lock acquirement try reached the acquirement time limit (:timeout option) the
186
+ # `RedisQueuedLocks::LockAcquirementTimeoutError` is raised (when `raise_errors` option
187
+ # set to `true`). The error message contains the lock key name and the timeout value).
188
+ # - <true> option adds the additional details to the error message:
189
+ # - current lock queue state (you can see which acquirer blocks your request and
190
+ # how much acquirers are in queue);
191
+ # - current lock data stored inside (for example: you can check the current acquirer and
192
+ # the lock meta state if you store some additional data there);
193
+ # - Realized as an option because of the additional lock data requires two additional Redis
194
+ # queries: (1) get the current lock from redis and (2) fetch the lock queue state;
195
+ # - These two additional Redis queries has async nature so you can receive
196
+ # inconsistent data of the lock and of the lock queue in your error emssage because:
197
+ # - required lock can be released after the error moment and before the error message build;
198
+ # - required lock can be obtained by other process after the error moment and
199
+ # before the error message build;
200
+ # - required lock queue can reach a state when the blocking acquirer start to obtain the lock
201
+ # and moved from the lock queue after the error moment and before the error message build;
202
+ # - You should consider the async nature of this error message and should use received data
203
+ # from error message correspondingly;
204
+ # - pre-configred in `config[:detailed_acq_timeout_error]`;
132
205
  # @option logger [::Logger,#debug]
133
206
  # - Logger object used from the configuration layer (see config[:logger]);
134
207
  # - See `RedisQueuedLocks::Logging::VoidLogger` for example;
@@ -189,7 +262,7 @@ class RedisQueuedLocks::Client
189
262
  #
190
263
  # @api public
191
264
  # @since 1.0.0
192
- # @version 1.6.0
265
+ # @version 1.8.0
193
266
  # rubocop:disable Metrics/MethodLength
194
267
  def lock(
195
268
  lock_name,
@@ -203,8 +276,10 @@ class RedisQueuedLocks::Client
203
276
  raise_errors: false,
204
277
  fail_fast: false,
205
278
  conflict_strategy: config[:default_conflict_strategy],
279
+ access_strategy: config[:default_access_strategy],
206
280
  identity: uniq_identity,
207
281
  meta: nil,
282
+ detailed_acq_timeout_error: config[:detailed_acq_timeout_error],
208
283
  logger: config[:logger],
209
284
  log_lock_try: config[:log_lock_try],
210
285
  instrumenter: config[:instrumenter],
@@ -236,7 +311,9 @@ class RedisQueuedLocks::Client
236
311
  identity:,
237
312
  fail_fast:,
238
313
  conflict_strategy:,
314
+ access_strategy:,
239
315
  meta:,
316
+ detailed_acq_timeout_error:,
240
317
  logger:,
241
318
  log_lock_try:,
242
319
  instrument:,
@@ -255,7 +332,7 @@ class RedisQueuedLocks::Client
255
332
  #
256
333
  # @api public
257
334
  # @since 1.0.0
258
- # @version 1.6.0
335
+ # @version 1.8.0
259
336
  # rubocop:disable Metrics/MethodLength
260
337
  def lock!(
261
338
  lock_name,
@@ -268,9 +345,11 @@ class RedisQueuedLocks::Client
268
345
  retry_jitter: config[:retry_jitter],
269
346
  fail_fast: false,
270
347
  conflict_strategy: config[:default_conflict_strategy],
348
+ access_strategy: config[:default_access_strategy],
271
349
  identity: uniq_identity,
272
350
  instrumenter: config[:instrumenter],
273
351
  meta: nil,
352
+ detailed_acq_timeout_error: config[:detailed_acq_timeout_error],
274
353
  logger: config[:logger],
275
354
  log_lock_try: config[:log_lock_try],
276
355
  instrument: nil,
@@ -297,9 +376,11 @@ class RedisQueuedLocks::Client
297
376
  logger:,
298
377
  log_lock_try:,
299
378
  meta:,
379
+ detailed_acq_timeout_error:,
300
380
  instrument:,
301
381
  instrumenter:,
302
382
  conflict_strategy:,
383
+ access_strategy:,
303
384
  log_sampling_enabled:,
304
385
  log_sampling_percent:,
305
386
  log_sampler:,
@@ -2,7 +2,6 @@
2
2
 
3
3
  # @api private
4
4
  # @since 1.0.0
5
- # @version 1.5.0
6
5
  module RedisQueuedLocks::Utilities
7
6
  module_function
8
7
 
@@ -5,6 +5,6 @@ module RedisQueuedLocks
5
5
  #
6
6
  # @api public
7
7
  # @since 0.0.1
8
- # @version 1.6.0
9
- VERSION = '1.6.0'
8
+ # @version 1.8.0
9
+ VERSION = '1.8.0'
10
10
  end
@@ -0,0 +1 @@
1
+ # frozen_string_literal: true
@@ -10,9 +10,25 @@ Gem::Specification.new do |spec|
10
10
  spec.authors = ['Rustam Ibragimov']
11
11
  spec.email = ['iamdaiver@gmail.com']
12
12
 
13
- spec.summary = 'Queued distributed locks based on Redis.'
14
- spec.description = 'Distributed locks with "lock acquisition queue" ' \
15
- 'capabilities based on the Redis Database.'
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
+ '|> Each lock request is put into the request queue ' \
21
+ '(each lock is hosted by it\'s own queue separately from other queues) and processed ' \
22
+ 'in order of their priority (FIFO). ' \
23
+ '|> Each lock request lives some period of time (RTTL) ' \
24
+ '(with requeue capabilities) which guarantees the request queue will never be stacked. ' \
25
+ '|> In addition to the classic `queued` (FIFO) strategy RQL supports ' \
26
+ '`random` (RANDOM) lock obtaining strategy when any acquirer from the lock queue ' \
27
+ 'can obtain the lock regardless the position in the queue. ' \
28
+ '|> Provides flexible invocation flow, parametrized limits ' \
29
+ '(lock request ttl, lock ttl, queue ttl, lock attempts limit, fast failing, etc), ' \
30
+ 'logging and instrumentation.'
31
+
16
32
  spec.homepage = 'https://github.com/0exp/redis_queued_locks'
17
33
  spec.license = 'MIT'
18
34
 
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.6.0
4
+ version: 1.8.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-05-25 00:00:00.000000000 Z
11
+ date: 2024-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis-client
@@ -38,8 +38,16 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.28'
41
- description: Distributed locks with "lock acquisition queue" capabilities based on
42
- the Redis Database.
41
+ description: '|> Distributed locks with "prioritized lock acquisition queue" capabilities
42
+ based on the Redis Database. |> Each lock request is put into the request queue
43
+ (each lock is hosted by it''s own queue separately from other queues) and processed
44
+ in order of their priority (FIFO). |> Each lock request lives some period of time
45
+ (RTTL) (with requeue capabilities) which guarantees the request queue will never
46
+ be stacked. |> In addition to the classic `queued` (FIFO) strategy RQL supports
47
+ `random` (RANDOM) lock obtaining strategy when any acquirer from the lock queue
48
+ can obtain the lock regardless the position in the queue. |> Provides flexible invocation
49
+ flow, parametrized limits (lock request ttl, lock ttl, queue ttl, lock attempts
50
+ limit, fast failing, etc), logging and instrumentation.'
43
51
  email:
44
52
  - iamdaiver@gmail.com
45
53
  executables: []
@@ -58,9 +66,15 @@ files:
58
66
  - lib/redis_queued_locks/acquier.rb
59
67
  - lib/redis_queued_locks/acquier/acquire_lock.rb
60
68
  - lib/redis_queued_locks/acquier/acquire_lock/delay_execution.rb
69
+ - lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue.rb
70
+ - lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue/log_visitor.rb
71
+ - lib/redis_queued_locks/acquier/acquire_lock/instr_visitor.rb
72
+ - lib/redis_queued_locks/acquier/acquire_lock/log_visitor.rb
61
73
  - lib/redis_queued_locks/acquier/acquire_lock/try_to_lock.rb
74
+ - lib/redis_queued_locks/acquier/acquire_lock/try_to_lock/log_visitor.rb
62
75
  - lib/redis_queued_locks/acquier/acquire_lock/with_acq_timeout.rb
63
76
  - lib/redis_queued_locks/acquier/acquire_lock/yield_expire.rb
77
+ - lib/redis_queued_locks/acquier/acquire_lock/yield_expire/log_visitor.rb
64
78
  - lib/redis_queued_locks/acquier/clear_dead_requests.rb
65
79
  - lib/redis_queued_locks/acquier/extend_lock_ttl.rb
66
80
  - lib/redis_queued_locks/acquier/is_locked.rb
@@ -87,6 +101,7 @@ files:
87
101
  - lib/redis_queued_locks/resource.rb
88
102
  - lib/redis_queued_locks/utilities.rb
89
103
  - lib/redis_queued_locks/version.rb
104
+ - lib/redis_queued_locks/watcher.rb
90
105
  - redis_queued_locks.gemspec
91
106
  homepage: https://github.com/0exp/redis_queued_locks
92
107
  licenses:
@@ -110,8 +125,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
110
125
  - !ruby/object:Gem::Version
111
126
  version: '0'
112
127
  requirements: []
113
- rubygems_version: 3.3.7
128
+ rubygems_version: 3.5.1
114
129
  signing_key:
115
130
  specification_version: 4
116
- summary: Queued distributed locks based on Redis.
131
+ summary: Distributed locks with "prioritized lock acquisition queue" capabilities
132
+ based on the Redis Database.
117
133
  test_files: []