redis_queued_locks 1.6.0 → 1.8.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.
@@ -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: []