redis_queued_locks 1.16.1 → 1.16.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0bd0b3bb446d6ce5af47949de25834b0c4f87a3fcb1090bf9604fba129354468
4
- data.tar.gz: b9c8c49560e193db92d63fc232c31fbdf1ea03b72b28fc778c3fcc22da3af1d1
3
+ metadata.gz: d49a1559431c569e92cfc1a9b56bd04d9942002aa6d79efcb533370f58b0c184
4
+ data.tar.gz: bc8fd235df24386a92275273de91d34804452eb085bbb5a2b7118eb4508319ab
5
5
  SHA512:
6
- metadata.gz: dcea0a7ee67e7a727fe0d92d88bf8f6b0a946c279fce3d43f34e6fe05844cf156e9679d91fcd12f450ebd9029a0aabd9f61b9c5224b7a88fa4551202bd716939
7
- data.tar.gz: 0c0b132e65106ce28f68a41278adc7981150b3a50d73952f55bfa22d0b735e8713924a20adca4caedd0fb744587a5675cbab0a78339c02d695b516129a2bd480
6
+ metadata.gz: 0e7d0944406f13a7a6bac3e59153998fca9731e184ef5da83d8d415af7185f61a4b260166895d3858c501f4ae93cf160fb6b4c5c33e248d2aa82c9bac2265216
7
+ data.tar.gz: 8aff1a1fb28cbc510edc30efbab0eed49bbb088feff6235959b314b24d705e0058c6d1a347356874fa2a4b930f7aaba62e7f6b48bebf2622e11600998055f719
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.16.2] - 2026-02-06
4
+ ### Fixed
5
+ - `lock_series` PoC:
6
+ - acquired locks are not released when the block of code invoked under the lock series fails with
7
+ an exception
8
+ - `raise_errors: true` option incorrectly suppresses the lock releasing when the lock series
9
+ reaches their obtaning limits
10
+
3
11
  ## [1.16.1] - 2026-01-28
4
12
  ### Changed
5
13
  - `lock_series` PoC:
@@ -30,7 +38,7 @@
30
38
  - lock series of lock simultainously (and release them all at the finish of your the invocation of block of code under the obtained locks);
31
39
  - exmaple: `client.lock_series("a", "b", "c")` (or in exceptional-based way `client.lock_series!("a", "b", "c")`;
32
40
  ### Changed
33
- - YARDOC documentation updates in order to prearet to the 100% yardoc-coverage;
41
+ - YARDOC documentation updates in order to prepare to the 100% yardoc-coverage;
34
42
  - updated dev deps;
35
43
  ### Fixed
36
44
  - fixed some yardoc documentation typos;
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2024-2025 Rustam Ibragimov
3
+ Copyright (c) 2024-2026 Rustam Ibragimov
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -8,7 +8,7 @@ Each lock request is put into the request queue (each lock is hosted by its own
8
8
 
9
9
  In addition to the classic `queued` (FIFO) strategy RQL supports `random` (RANDOM) lock obtaining strategy when any acquirer from the lock queue can obtain the lock regardless the position in the queue.
10
10
 
11
- Provides flexible invocation flow, parametrized limits (lock request ttl, lock ttl, queue ttl, lock attempts limit, fast failing, etc), logging and instrumentation.
11
+ Provides flexible invocation flow, parametrized limits (lock request ttl, lock ttl, queue ttl, lock attempts limit, fast failing, etc), **zombie locks elimination**, support for **reentrant locks**, logging and instrumentation (and much more).
12
12
 
13
13
  ---
14
14
 
@@ -23,8 +23,8 @@ Provides flexible invocation flow, parametrized limits (lock request ttl, lock t
23
23
  - [Usage](#usage)
24
24
  - [lock](#lock---obtain-a-lock)
25
25
  - [lock!](#lock---exceptional-lock-obtaining)
26
- - [lock_series (PoC)](#lock_series---poc-acquire-a-series-of-locks)
27
- - [lock_series! (PoC)](#lock_series---poc-exceptional-lock_series)
26
+ - [lock_series](#lock_series---poc-acquire-a-series-of-locks) (PoC)
27
+ - [lock_series!](#lock_series---poc-exceptional-lock_series) (PoC)
28
28
  - [lock_info](#lock_info)
29
29
  - [queue_info](#queue_info)
30
30
  - [locked?](#locked)
@@ -86,10 +86,10 @@ Provides flexible invocation flow, parametrized limits (lock request ttl, lock t
86
86
 
87
87
  <sup>\[[back to top](#table-of-contents)\]</sup>
88
88
 
89
- - Redis Version: `~> 7.x`;
89
+ - Redis Version: `>= 7`, `~> 8.x`;
90
90
  - Redis Protocol: `RESP3`;
91
91
  - gem `redis-client`: `~> 0.20`;
92
- - Ruby: `>= 3.1`;
92
+ - Ruby: `>= 3.3`;
93
93
 
94
94
  ---
95
95
 
@@ -854,13 +854,14 @@ See `#lock` method [documentation](#lock---obtain-a-lock).
854
854
 
855
855
  #### #lock_series - (PoC) acquire a series of locks
856
856
 
857
- > (IMPORTANT!) "Proof of Concept" realization. Will be reworked in the future (very-very soon)
857
+ <sup>\[[back to top](#usage)\]</sup>
858
+
859
+ > (IMPORTANT!) "Proof of Concept" realization. Will be reworked in the future.
858
860
 
859
861
  `lock_series` - acquire a series of locks simultaniously and hold them all while your block of code is executing
860
862
  or (if block is not passed) while all locks will not expire.
861
863
 
862
- If it is not possible to obtain all locks at the same time (taking into queue ttl, retry attempts count for each lock, etc)
863
- - no any lock will be acquired.
864
+ If it is not possible to obtain all locks at the same time (taking into queue ttl, retry attempts count for each lock, etc) no any lock will be acquired.
864
865
 
865
866
  Method options is the same as for `lock` method: `retry_count`, `retry_jitter`, `ttl`, `queue_ttl`, etc. Each option will be
866
867
  applied with the same value to the each lock acquirement process (for each lock in a series separately).
@@ -880,7 +881,7 @@ applied with the same value to the each lock acquirement process (for each lock
880
881
 
881
882
  ##### How to use:
882
883
 
883
- - method signature is the same as the `lock` method;
884
+ - method signature is the same as the `#lock`;
884
885
 
885
886
  ```ruby
886
887
  # typical logic-oriented way
@@ -937,7 +938,7 @@ client.lock_seires('c', 'a', 'b') # ... `a` is still obtained
937
938
  }
938
939
  ```
939
940
 
940
- ##### New instrumentaiton events and logs:
941
+ ###### New instrumentaiton events:
941
942
 
942
943
  ```ruby
943
944
  # NEW instrumentation events (examples)
@@ -945,6 +946,8 @@ client.lock_seires('c', 'a', 'b') # ... `a` is still obtained
945
946
  "redis_queued_locks.lock_series_hold_and_release" => # {lock_keys: ["rql:lock:x", "rql:lock:y", "rql:lock:z"], hold_time: 0.29, ttl: 5000, acq_id: "rql:acq:4486/1696/1704/1712/e6fd0da7991e4303", hst_id: "rql:hst:4486/1696/1712/e6fd0da7991e4303", ts: 1769627106.4717052, acq_time: 4.26, instrument: nil}
946
947
  ```
947
948
 
949
+ ###### New logs:
950
+
948
951
  ```shell
949
952
  # NEW logs (examples)
950
953
  [redis_queued_locks.start_lock_series_obtaining] lock_keys => '["rql:lock:a", "rql:lock:b"]'queue_ttl => 15 acq_id => 'rql:acq:4486/1696/1704/1712/e6fd0da7991e4303' hst_id => 'rql:hst:4486/1696/1712/e6fd0da7991e4303' acs_strat => 'queued'
@@ -956,6 +959,8 @@ client.lock_seires('c', 'a', 'b') # ... `a` is still obtained
956
959
 
957
960
  #### #lock_series! - (PoC) exceptional `lock_series`
958
961
 
962
+ <sup>\[[back to top](#usage)\]</sup>
963
+
959
964
  > (IMPORTANT!) "Proof of Concept" realization. Will be reworked in the future (very-very soon)
960
965
 
961
966
  For more details see `lock_series` [docs](#lock_series---poc-acquire-a-series-of-locks)
@@ -2430,7 +2435,8 @@ Detalized event semantics and payload structure:
2430
2435
  some GVL-related things and problem situations when the global watcher thread is "dead";
2431
2436
  - lock request prioritization;
2432
2437
  - **strict redlock algorithm support** (support for many `RedisClient` instances that are fully independent (distributed redis instances));
2433
- - `#lock_series` - acquire a series of locks:
2438
+ - #lock_series` - acquire a series of locks:
2439
+ - (NOTE: "Proof of Concept" implementation is ready to use);
2434
2440
  ```ruby
2435
2441
  rql.lock_series('lock_a', 'lock_b', 'lock_c') { puts 'locked' }
2436
2442
  ```
@@ -2477,6 +2483,8 @@ Detalized event semantics and payload structure:
2477
2483
  - **Research**: support for `Garnet` database backend (https://microsoft.github.io/) (https://github.com/microsoft/garnet);
2478
2484
  - add a library-level exception, when RQL-related key in Redis (required for its logic) has incompatible type (means: some other program uses our key with their own type and logic and RQL can't work properly);
2479
2485
  - yardoc docs with CI check (full doc coverage check);
2486
+ - split *exception* inheritance to the groups: `lock obtaining errors`, `block invocation errors`, `swarm errors`, and other groups (research possible groups):
2487
+ - in some cases we need to intercept "Lock Obtaining Process Erros", in other cases: "Block Invocation Errors", and so on (in `Lock Serirs PoC` for example);
2480
2488
 
2481
2489
  ---
2482
2490
 
@@ -15,7 +15,7 @@ module RedisQueuedLocks::Acquirer::LockSeriesPoC # steep:ignore
15
15
  class << self
16
16
  # @api private
17
17
  # @since 1.16.0
18
- # @version 1.16.1
18
+ # @version 1.16.2
19
19
  def lock_series_poc( # steep:ignore
20
20
  redis,
21
21
  lock_names,
@@ -175,8 +175,12 @@ module RedisQueuedLocks::Acquirer::LockSeriesPoC # steep:ignore
175
175
  instr_sampler:,
176
176
  instr_sample_this:
177
177
  )
178
- rescue => error
179
- if raise_errors && successfully_acquired_locks.any?
178
+ rescue RedisQueuedLocks::LockAlreadyObtainedError,
179
+ RedisQueuedLocks::LockAcquirementIntermediateTimeoutError,
180
+ RedisQueuedLocks::LockAcquirementTimeoutError,
181
+ RedisQueuedLocks::LockAcquirementRetryLimitError,
182
+ RedisQueuedLocks::ConflictLockObtainError => error
183
+ if successfully_acquired_locks.any?
180
184
  # NOTE: release all previously acquired locks if any next lock is already locked
181
185
  successfully_acquired_locks.each do |operation_result|
182
186
  lock_key = RedisQueuedLocks::Resource.prepare_lock_key(operation_result[:lock_name])
@@ -187,7 +191,8 @@ module RedisQueuedLocks::Acquirer::LockSeriesPoC # steep:ignore
187
191
  end
188
192
  end
189
193
  end
190
- raise(error)
194
+
195
+ raise(error) if raise_errors
191
196
  end
192
197
 
193
198
  if result[:ok]
@@ -225,61 +230,67 @@ module RedisQueuedLocks::Acquirer::LockSeriesPoC # steep:ignore
225
230
  RedisQueuedLocks::Resource::REDIS_TIMESHIFT_ERROR
226
231
  ).ceil(2)
227
232
 
228
- yield_result = yield_expire( # steep:ignore
229
- redis,
230
- logger,
231
- lock_keys_for_instrumentation.last,
232
- acquirer_id_for_instrumentation,
233
- host_id_for_instrumentation,
234
- access_strategy,
235
- timed,
236
- ttl_shift,
237
- ttl,
238
- queue_ttl,
239
- meta,
240
- log_sampled,
241
- instr_sampled,
242
- false, # should_expire (expire manually)
243
- false, # should_decrease (expire manually)
244
- &block
245
- )
233
+ yield_result = nil
234
+ is_lock_manually_released = nil
235
+ hold_time = nil
246
236
 
247
- is_lock_manually_released = false
237
+ begin
238
+ yield_result = yield_expire( # steep:ignore
239
+ redis,
240
+ logger,
241
+ lock_keys_for_instrumentation.last,
242
+ acquirer_id_for_instrumentation,
243
+ host_id_for_instrumentation,
244
+ access_strategy,
245
+ timed,
246
+ ttl_shift,
247
+ ttl,
248
+ queue_ttl,
249
+ meta,
250
+ log_sampled,
251
+ instr_sampled,
252
+ false, # should_expire (expire manually)
253
+ false, # should_decrease (expire manually)
254
+ &block
255
+ )
256
+ ensure
257
+ is_lock_manually_released = false
248
258
 
249
- # expire locks manually
250
- if block_given?
251
- redis.with do |conn|
252
- # use transaction in order to exclude any cross-locking during the group expiration
253
- conn.multi(watch: lock_keys_for_instrumentation) do |transaction|
254
- lock_keys_for_instrumentation.each do |lock_key|
255
- transaction.call('EXPIRE', lock_key, '0')
259
+ # expire locks manually
260
+ if block_given?
261
+ redis.with do |conn|
262
+ # use transaction in order to exclude any cross-locking during the group expiration
263
+ conn.multi(watch: lock_keys_for_instrumentation) do |transaction|
264
+ lock_keys_for_instrumentation.each do |lock_key|
265
+ transaction.call('EXPIRE', lock_key, '0')
266
+ end
256
267
  end
257
268
  end
269
+ is_lock_manually_released = true
258
270
  end
259
- is_lock_manually_released = true
260
- end
261
271
 
262
- rel_time = RedisQueuedLocks::Utilities.clock_gettime
263
- hold_time = ((rel_time - acq_end_time) / 1_000.0).ceil(2)
264
- ts = Time.now.to_f
272
+ rel_time = RedisQueuedLocks::Utilities.clock_gettime
273
+ hold_time = ((rel_time - acq_end_time) / 1_000.0).ceil(2)
274
+ ts = Time.now.to_f
265
275
 
266
- RedisQueuedLocks::Acquirer::LockSeriesPoC::LogVisitor.expire_lock_series( # steep:ignore
267
- logger, log_sampled, lock_keys_for_instrumentation,
268
- queue_ttl, acquirer_id_for_instrumentation, host_id_for_instrumentation, access_strategy
269
- ) if is_lock_manually_released
276
+ RedisQueuedLocks::Acquirer::LockSeriesPoC::LogVisitor.expire_lock_series( # steep:ignore
277
+ logger, log_sampled, lock_keys_for_instrumentation,
278
+ queue_ttl, acquirer_id_for_instrumentation, host_id_for_instrumentation, access_strategy
279
+ ) if is_lock_manually_released
270
280
 
271
- RedisQueuedLocks::Acquirer::LockSeriesPoC::InstrVisitor.lock_series_hold_and_release( # steep:ignore
272
- instrumenter,
273
- instr_sampled,
274
- lock_keys_for_instrumentation,
275
- ttl,
276
- acquirer_id_for_instrumentation,
277
- host_id_for_instrumentation,
278
- ts,
279
- acq_time,
280
- hold_time,
281
- instrument
282
- ) if is_lock_manually_released
281
+ RedisQueuedLocks::Acquirer::LockSeriesPoC::InstrVisitor.lock_series_hold_and_release( # steep:ignore
282
+ instrumenter,
283
+ instr_sampled,
284
+ lock_keys_for_instrumentation,
285
+ ttl,
286
+ acquirer_id_for_instrumentation,
287
+ host_id_for_instrumentation,
288
+ ts,
289
+ acq_time,
290
+ hold_time,
291
+ instrument
292
+ ) if is_lock_manually_released
293
+ end
283
294
 
284
295
  if detailed_result
285
296
  {
@@ -5,6 +5,6 @@ module RedisQueuedLocks
5
5
  #
6
6
  # @api public
7
7
  # @since 0.0.1
8
- # @version 1.16.1
9
- VERSION = '1.16.1'
8
+ # @version 1.16.2
9
+ VERSION = '1.16.2'
10
10
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis_queued_locks
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.16.1
4
+ version: 1.16.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rustam Ibragimov