redis_queued_locks 0.0.30 → 0.0.32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +56 -27
- data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock.rb +5 -2
- data/lib/redis_queued_locks/acquier/acquire_lock/with_acq_timeout.rb +5 -3
- data/lib/redis_queued_locks/acquier/acquire_lock/yield_with_expire.rb +5 -3
- data/lib/redis_queued_locks/acquier/acquire_lock.rb +51 -16
- data/lib/redis_queued_locks/acquier/lock_info.rb +12 -13
- data/lib/redis_queued_locks/acquier/queue_info.rb +6 -6
- data/lib/redis_queued_locks/client.rb +16 -8
- data/lib/redis_queued_locks/version.rb +2 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d33fd5af73686a34765eb95c54fe9dc28b107a01768e41b2a28150dffdc72a60
|
4
|
+
data.tar.gz: 0ac04f452fbd00b01df535a48dd724e360ed66f42459e33fbf989427531c6b6a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 419d36772547c3a7010353d6589b62c442cd7e2575a1c96fcf8ebcee9be83c002a44de7a5dc6de8faa6e32c76f044bf5eaf659ddaf156e8eb3093587dab54e90
|
7
|
+
data.tar.gz: 28ba2de724d7d7540d967e9ade24ca6d65126af526224ae90f418c04e58618ff1aa856911d9eef363b004272fda73a0ce5ddf83a52460e4d78f09dabdd9fba3f
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.0.32] - 2024-03-26
|
4
|
+
### Added
|
5
|
+
- Support for custom metadata that merged to the lock data. This data also returned from `RedisQueudLocks::Client#lock_info` method;
|
6
|
+
- Custom metadata shou;d be represented as a `key => value` `Hash` data (or `NilClass` instead);
|
7
|
+
- Custom metadata values is returned as raw data from Redis (commonly as strings);
|
8
|
+
- Custom metadata can not contain reserved lock data keys;
|
9
|
+
- Reduced some memory consuption;
|
10
|
+
### Changed
|
11
|
+
- `RedisQueuedLocks::Client#lock_info` - has keys is changed from `Symbol` type to `String` type;
|
12
|
+
- `RedisQueuedLocks::Client#queue_info` - hash keys is changed from `Symbol` type to `String` type;
|
13
|
+
|
14
|
+
## [0.0.31] - 2024-03-25
|
15
|
+
### Changed
|
16
|
+
- `:metadata` renamed to `:instrument` in order to reflect it's domain area;
|
17
|
+
- `:metadata` is renamed to `:meta` and reserved for the future updates;
|
18
|
+
|
3
19
|
## [0.0.30] - 2024-03-23
|
4
20
|
### Fixed
|
5
21
|
- Re-enqueue problem: fixed a problem when the expired lock requests were infinitly re-added to the lock queue
|
data/README.md
CHANGED
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
Distributed locks with "lock acquisition queue" capabilities based on the Redis Database.
|
4
4
|
|
5
|
-
|
5
|
+
Provides flexible invocation flow, parametrized limits (lock request ttl, lock ttls, queue ttls, fast failing, etc), logging and instrumentation.
|
6
|
+
|
7
|
+
Each lock request is put into the request queue (each lock is hosted by it's own queue separately from other queues) and processed in order of their priority (FIFO). Each lock request lives some period of time (RTTL) which guarantees the request queue will never be stacked.
|
6
8
|
|
7
9
|
---
|
8
10
|
|
@@ -14,7 +16,7 @@ Each lock request is put into the request queue and processed in order of their
|
|
14
16
|
- [Configuration](#configuration)
|
15
17
|
- [Usage](#usage)
|
16
18
|
- [lock](#lock---obtain-a-lock)
|
17
|
-
- [lock!](#lock---
|
19
|
+
- [lock!](#lock---exceptional-lock-obtaining)
|
18
20
|
- [lock_info](#lock_info)
|
19
21
|
- [queue_info](#queue_info)
|
20
22
|
- [locked?](#locked)
|
@@ -36,7 +38,7 @@ Each lock request is put into the request queue and processed in order of their
|
|
36
38
|
|
37
39
|
### Algorithm
|
38
40
|
|
39
|
-
> Each lock request is put into the request queue and processed in order of their priority (FIFO). Each lock request lives some period of time (RTTL) which guarantees that the request queue will never be stacked.
|
41
|
+
> Each lock request is put into the request queue (each lock is hosted by it's own queue separately from other queues) and processed in order of their priority (FIFO). Each lock request lives some period of time (RTTL) which guarantees that the request queue will never be stacked.
|
40
42
|
|
41
43
|
**Soon**: detailed explanation.
|
42
44
|
|
@@ -194,7 +196,8 @@ def lock(
|
|
194
196
|
raise_errors: false,
|
195
197
|
fail_fast: false,
|
196
198
|
identity: uniq_identity, # (attr_accessor) calculated during client instantiation via config[:uniq_identifier] proc;
|
197
|
-
|
199
|
+
meta: nil,
|
200
|
+
instrument: nil,
|
198
201
|
logger: config[:logger],
|
199
202
|
log_lock_try: config[:log_lock_try],
|
200
203
|
&block
|
@@ -232,8 +235,11 @@ def lock(
|
|
232
235
|
pods or/and nodes of your application;
|
233
236
|
- It is calculated once during `RedisQueuedLock::Client` instantiation and stored in `@uniq_identity`
|
234
237
|
ivar (accessed via `uniq_dentity` accessor method);
|
235
|
-
- `
|
236
|
-
- A custom metadata wich will be passed to the
|
238
|
+
- `meta` - `[NilClass,Hash<String|Symbol,Any>]`
|
239
|
+
- A custom metadata wich will be passed to the lock data in addition to the existing data;
|
240
|
+
- Custom metadata can not contain reserved lock data keys (such as `lock_key`, `acq_id`, `ts`, `ini_ttl`, `rem_ttl`);
|
241
|
+
- `instrument` - `[NilClass,Any]`
|
242
|
+
- Custom instrumentation data wich will be passed to the instrumenter's payload with :instrument key;
|
237
243
|
- `logger` - `[::Logger,#debug]`
|
238
244
|
- Logger object used from the configuration layer (see config[:logger]);
|
239
245
|
- See `RedisQueuedLocks::Logging::VoidLogger` for example;
|
@@ -293,7 +299,8 @@ def lock!(
|
|
293
299
|
retry_jitter: config[:retry_jitter],
|
294
300
|
identity: uniq_identity,
|
295
301
|
fail_fast: false,
|
296
|
-
|
302
|
+
meta: nil,
|
303
|
+
instrument: nil,
|
297
304
|
logger: config[:logger],
|
298
305
|
log_lock_try: config[:log_lock_try],
|
299
306
|
&block
|
@@ -309,22 +316,42 @@ See `#lock` method [documentation](#lock---obtain-a-lock).
|
|
309
316
|
- get the lock information;
|
310
317
|
- returns `nil` if lock does not exist;
|
311
318
|
- lock data (`Hash<Symbol,String|Integer>`):
|
312
|
-
- `lock_key` - `string` - lock key in redis;
|
313
|
-
- `acq_id` - `string` - acquier identifier (process_id/thread_id/fiber_id/ractor_id/identity);
|
314
|
-
- `ts` - `integer`/`epoch` - the time lock was obtained;
|
315
|
-
- `init_ttl` - `integer` - (milliseconds) initial lock key ttl;
|
316
|
-
- `rem_ttl` - `integer` - (milliseconds) remaining lock key ttl;
|
319
|
+
- `"lock_key"` - `string` - lock key in redis;
|
320
|
+
- `"acq_id"` - `string` - acquier identifier (process_id/thread_id/fiber_id/ractor_id/identity);
|
321
|
+
- `"ts"` - `integer`/`epoch` - the time lock was obtained;
|
322
|
+
- `"init_ttl"` - `integer` - (milliseconds) initial lock key ttl;
|
323
|
+
- `"rem_ttl"` - `integer` - (milliseconds) remaining lock key ttl;
|
324
|
+
- custom metadata keys - `String` - custom metadata passed to the `lock`/`lock!`
|
325
|
+
methods via `meta:` keyword argument (see [lock]((#lock---obtain-a-lock)) method documentation);
|
326
|
+
|
327
|
+
```ruby
|
328
|
+
# without custom metadata
|
329
|
+
rql.lock_info("your_lock_name")
|
330
|
+
|
331
|
+
# =>
|
332
|
+
{
|
333
|
+
"lock_key" => "rql:lock:your_lock_name",
|
334
|
+
"acq_id" => "rql:acq:123/456/567/678/374dd74324",
|
335
|
+
"ts" => 123456789,
|
336
|
+
"ini_ttl" => 123456789,
|
337
|
+
"rem_ttl" => 123456789
|
338
|
+
}
|
339
|
+
```
|
317
340
|
|
318
341
|
```ruby
|
342
|
+
# with custom metadata
|
343
|
+
rql.lock("your_lock_name", meta: { "kek" => "pek", "bum" => 123 })
|
319
344
|
rql.lock_info("your_lock_name")
|
320
345
|
|
321
346
|
# =>
|
322
347
|
{
|
323
|
-
lock_key
|
324
|
-
acq_id
|
325
|
-
ts
|
326
|
-
ini_ttl
|
327
|
-
rem_ttl
|
348
|
+
"lock_key" => "rql:lock:your_lock_name",
|
349
|
+
"acq_id" => "rql:acq:123/456/567/678/374dd74324",
|
350
|
+
"ts" => 123456789,
|
351
|
+
"ini_ttl" => 123456789,
|
352
|
+
"rem_ttl" => 123456789,
|
353
|
+
"kek" => "pek",
|
354
|
+
"bum" => "123" # NOTE: returned as a raw string directly from Redis
|
328
355
|
}
|
329
356
|
```
|
330
357
|
|
@@ -339,10 +366,10 @@ rql.lock_info("your_lock_name")
|
|
339
366
|
- represents the acquier identifier and their score as an array of hashes;
|
340
367
|
- returns `nil` if lock queue does not exist;
|
341
368
|
- lock queue data (`Hash<Symbol,String|Array<Hash<Symbol,String|Numeric>>`):
|
342
|
-
- `lock_queue` - `string` - lock queue key in redis;
|
343
|
-
- `queue` - `array` - an array of lock requests (array of hashes):
|
344
|
-
- `acq_id` - `string` - acquier identifier (process_id/thread_id/fiber_id/ractor_id/identity by default);
|
345
|
-
- `score` - `float`/`epoch` - time when the lock request was made (epoch);
|
369
|
+
- `"lock_queue"` - `string` - lock queue key in redis;
|
370
|
+
- `"queue"` - `array` - an array of lock requests (array of hashes):
|
371
|
+
- `"acq_id"` - `string` - acquier identifier (process_id/thread_id/fiber_id/ractor_id/identity by default);
|
372
|
+
- `"score"` - `float`/`epoch` - time when the lock request was made (epoch);
|
346
373
|
|
347
374
|
```
|
348
375
|
| Returns an information about the required lock queue by the lock name. The result
|
@@ -357,11 +384,11 @@ rql.queue_info("your_lock_name")
|
|
357
384
|
|
358
385
|
# =>
|
359
386
|
{
|
360
|
-
lock_queue
|
361
|
-
queue
|
362
|
-
{ acq_id
|
363
|
-
{ acq_id
|
364
|
-
{ acq_id
|
387
|
+
"lock_queue" => "rql:lock_queue:your_lock_name",
|
388
|
+
"queue" => [
|
389
|
+
{ "acq_id" => "rql:acq:123/456/567/678/fa76df9cc2", "score" => 1},
|
390
|
+
{ "acq_id" => "rql:acq:123/567/456/679/c7bfcaf4f9", "score" => 2},
|
391
|
+
{ "acq_id" => "rql:acq:555/329/523/127/7329553b11", "score" => 3},
|
365
392
|
# ...etc
|
366
393
|
]
|
367
394
|
}
|
@@ -604,7 +631,8 @@ Detalized event semantics and payload structure:
|
|
604
631
|
- `100%` test coverage;
|
605
632
|
- per-block-holding-the-lock sidecar `Ractor` and `in progress queue` in RedisDB that will extend
|
606
633
|
the acquired lock for long-running blocks of code (that invoked "under" the lock
|
607
|
-
whose ttl may expire before the block execution completes)
|
634
|
+
whose ttl may expire before the block execution completes). It only makes sens for non-`timed` locks
|
635
|
+
(for those locks where otaned with `timed: false` option);
|
608
636
|
- an ability to add custom metadata to the lock and an ability to read this data;
|
609
637
|
- lock prioritization;
|
610
638
|
- support for LIFO strategy;
|
@@ -613,6 +641,7 @@ Detalized event semantics and payload structure:
|
|
613
641
|
- `RedisQueuedLocks::Acquier::Try.try_to_lock` - detailed successful result analization;
|
614
642
|
- better code stylization and interesting refactorings;
|
615
643
|
- dead queue cleanup;
|
644
|
+
- statistics with UI;
|
616
645
|
- support for `Dragonfly` DB backend;
|
617
646
|
- support for `Garnet` DB backend;
|
618
647
|
|
@@ -17,6 +17,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
|
|
17
17
|
# @param ttl [Integer]
|
18
18
|
# @param queue_ttl [Integer]
|
19
19
|
# @param fail_fast [Boolean]
|
20
|
+
# @param meta [NilClass,Hash<String|Symbol,Any>]
|
20
21
|
# @return [Hash<Symbol,Any>] Format: { ok: true/false, result: Symbol|Hash<Symbol,Any> }
|
21
22
|
#
|
22
23
|
# @api private
|
@@ -32,7 +33,8 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
|
|
32
33
|
acquier_position,
|
33
34
|
ttl,
|
34
35
|
queue_ttl,
|
35
|
-
fail_fast
|
36
|
+
fail_fast,
|
37
|
+
meta
|
36
38
|
)
|
37
39
|
# Step X: intermediate invocation results
|
38
40
|
inter_result = nil
|
@@ -230,7 +232,8 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
|
|
230
232
|
lock_key,
|
231
233
|
'acq_id', acquier_id,
|
232
234
|
'ts', (timestamp = Time.now.to_f),
|
233
|
-
'ini_ttl', ttl
|
235
|
+
'ini_ttl', ttl,
|
236
|
+
*(meta.to_a if meta != nil)
|
234
237
|
)
|
235
238
|
|
236
239
|
# Step 6.3: set the lock expiration time in order to prevent "infinite locks"
|
@@ -21,9 +21,11 @@ module RedisQueuedLocks::Acquier::AcquireLock::WithAcqTimeout
|
|
21
21
|
on_timeout.call unless on_timeout == nil
|
22
22
|
|
23
23
|
if raise_errors
|
24
|
-
raise(
|
25
|
-
|
26
|
-
|
24
|
+
raise(
|
25
|
+
RedisQueuedLocks::LockAcquiermentTimeoutError,
|
26
|
+
"Failed to acquire the lock \"#{lock_key}\" " \
|
27
|
+
"for the given timeout (#{timeout} seconds)."
|
28
|
+
)
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
@@ -63,8 +63,10 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldWithExpire
|
|
63
63
|
def yield_with_timeout(timeout, lock_key, lock_ttl, &block)
|
64
64
|
::Timeout.timeout(timeout, &block)
|
65
65
|
rescue ::Timeout::Error
|
66
|
-
raise(
|
67
|
-
|
68
|
-
|
66
|
+
raise(
|
67
|
+
RedisQueuedLocks::TimedLockTimeoutError,
|
68
|
+
"Passed <timed> block of code exceeded " \
|
69
|
+
"the lock TTL (lock: \"#{lock_key}\", ttl: #{lock_ttl})"
|
70
|
+
)
|
69
71
|
end
|
70
72
|
end
|
@@ -67,8 +67,9 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
67
67
|
# @option fail_fast [Boolean]
|
68
68
|
# Should the required lock to be checked before the try and exit immidetly if lock is
|
69
69
|
# already obtained.
|
70
|
-
# @option
|
71
|
-
# - A custom metadata wich will be passed to the
|
70
|
+
# @option meta [NilClass,Hash<String|Symbol,Any>]
|
71
|
+
# - A custom metadata wich will be passed to the lock data in addition to the existing data;
|
72
|
+
# - Metadata can not contain reserved lock data keys;
|
72
73
|
# @option logger [::Logger,#debug]
|
73
74
|
# - Logger object used from the configuration layer (see config[:logger]);
|
74
75
|
# - See RedisQueuedLocks::Logging::VoidLogger for example;
|
@@ -76,6 +77,9 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
76
77
|
# - should be logged the each try of lock acquiring (a lot of logs can be generated depending
|
77
78
|
# on your retry configurations);
|
78
79
|
# - see `config[:log_lock_try]`;
|
80
|
+
# @option instrument [NilClass,Any]
|
81
|
+
# - Custom instrumentation data wich will be passed to the instrumenter's payload
|
82
|
+
# with :instrument key;
|
79
83
|
# @param [Block]
|
80
84
|
# A block of code that should be executed after the successfully acquired lock.
|
81
85
|
# @return [RedisQueuedLocks::Data,Hash<Symbol,Any>,yield]
|
@@ -102,11 +106,38 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
102
106
|
instrumenter:,
|
103
107
|
identity:,
|
104
108
|
fail_fast:,
|
105
|
-
|
109
|
+
meta:,
|
110
|
+
instrument:,
|
106
111
|
logger:,
|
107
112
|
log_lock_try:,
|
108
113
|
&block
|
109
114
|
)
|
115
|
+
# Step 0: Prevent argument type incompatabilities
|
116
|
+
# Step 0.1: prevent :meta incompatabiltiies (type)
|
117
|
+
case meta # NOTE: do not ask why case/when is used here
|
118
|
+
when Hash, NilClass then nil
|
119
|
+
else
|
120
|
+
raise(
|
121
|
+
RedisQueuedLocks::ArgumentError,
|
122
|
+
"`:meta` argument should be a type of NilClass or Hash, got #{meta.class}."
|
123
|
+
)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Step 0.2: prevent :meta incompatabiltiies (structure)
|
127
|
+
if meta == ::Hash && (meta.keys.any? do |key|
|
128
|
+
key == 'acq_id' ||
|
129
|
+
key == 'ts' ||
|
130
|
+
key == 'ini_ttl' ||
|
131
|
+
key == 'lock_key' ||
|
132
|
+
key == 'rem_ttl'
|
133
|
+
end)
|
134
|
+
raise(
|
135
|
+
RedisQueuedLocks::ArgumentError,
|
136
|
+
'`:meta` keys can not overlap reserved lock data keys' \
|
137
|
+
'"acq_id", "ts", "ini_ttl", "lock_key", "rem_ttl"'
|
138
|
+
)
|
139
|
+
end
|
140
|
+
|
110
141
|
# Step 1: prepare lock requirements (generate lock name, calc lock ttl, etc).
|
111
142
|
acquier_id = RedisQueuedLocks::Resource.acquier_identifier(
|
112
143
|
process_id,
|
@@ -185,7 +216,8 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
185
216
|
acquier_position,
|
186
217
|
lock_ttl,
|
187
218
|
queue_ttl,
|
188
|
-
fail_fast
|
219
|
+
fail_fast,
|
220
|
+
meta
|
189
221
|
) => { ok:, result: }
|
190
222
|
|
191
223
|
acq_end_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
@@ -215,7 +247,7 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
215
247
|
acq_id: result[:acq_id],
|
216
248
|
ts: result[:ts],
|
217
249
|
acq_time: acq_time,
|
218
|
-
|
250
|
+
instrument:
|
219
251
|
})
|
220
252
|
end
|
221
253
|
|
@@ -233,9 +265,10 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
233
265
|
elsif fail_fast && acq_process[:result] == :fail_fast_no_try
|
234
266
|
acq_process[:should_try] = false
|
235
267
|
if raise_errors
|
236
|
-
raise(
|
237
|
-
|
238
|
-
|
268
|
+
raise(
|
269
|
+
RedisQueuedLocks::LockAlreadyObtainedError,
|
270
|
+
"Lock \"#{lock_key}\" is already obtained."
|
271
|
+
)
|
239
272
|
end
|
240
273
|
else
|
241
274
|
# Step 2.1.b: failed acquirement => retry
|
@@ -255,14 +288,16 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
255
288
|
|
256
289
|
# NOTE: check and raise an error
|
257
290
|
if fail_fast && raise_errors
|
258
|
-
raise(
|
259
|
-
|
260
|
-
|
291
|
+
raise(
|
292
|
+
RedisQueuedLocks::LockAlreadyObtainedError,
|
293
|
+
"Lock \"#{lock_key}\" is already obtained."
|
294
|
+
)
|
261
295
|
elsif raise_errors
|
262
|
-
raise(
|
263
|
-
|
264
|
-
|
265
|
-
|
296
|
+
raise(
|
297
|
+
RedisQueuedLocks::LockAcquiermentRetryLimitError,
|
298
|
+
"Failed to acquire the lock \"#{lock_key}\" " \
|
299
|
+
"for the given retry_count limit (#{retry_count} times)."
|
300
|
+
)
|
266
301
|
end
|
267
302
|
else
|
268
303
|
# NOTE:
|
@@ -307,7 +342,7 @@ module RedisQueuedLocks::Acquier::AcquireLock
|
|
307
342
|
ts: acq_process[:lock_info][:ts],
|
308
343
|
lock_key: acq_process[:lock_info][:lock_key],
|
309
344
|
acq_time: acq_process[:acq_time],
|
310
|
-
|
345
|
+
instrument:
|
311
346
|
})
|
312
347
|
end
|
313
348
|
end
|
@@ -6,14 +6,14 @@ module RedisQueuedLocks::Acquier::LockInfo
|
|
6
6
|
class << self
|
7
7
|
# @param redis_client [RedisClient]
|
8
8
|
# @param lock_name [String]
|
9
|
-
# @return [Hash<
|
9
|
+
# @return [Hash<String,String|Numeric>,NilClass]
|
10
10
|
# - `nil` is returned when lock key does not exist or expired;
|
11
11
|
# - result format: {
|
12
|
-
# lock_key
|
13
|
-
# acq_id
|
14
|
-
# ts
|
15
|
-
# ini_ttl
|
16
|
-
# rem_ttl
|
12
|
+
# 'lock_key' => "rql:lock:your_lockname", # acquired lock key
|
13
|
+
# 'acq_id' => "rql:acq:process_id/thread_id", # lock acquier identifier
|
14
|
+
# 'ts' => 123456789.2649841, # <locked at> time stamp (epoch, seconds.microseconds)
|
15
|
+
# 'ini_ttl' => 123456789, # initial lock key ttl (milliseconds),
|
16
|
+
# 'rem_ttl' => 123456789, # remaining lock key ttl (milliseconds)
|
17
17
|
# }
|
18
18
|
#
|
19
19
|
# @api private
|
@@ -43,13 +43,12 @@ module RedisQueuedLocks::Acquier::LockInfo
|
|
43
43
|
# NOTE: the result of MULTI-command is an array of results of each internal command
|
44
44
|
# - result[0] (HGETALL) (Hash<String,String>)
|
45
45
|
# - result[1] (PTTL) (Integer)
|
46
|
-
|
47
|
-
lock_key
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
}
|
46
|
+
hget_cmd_res.tap do |lock_data|
|
47
|
+
lock_data['lock_key'] = lock_key
|
48
|
+
lock_data['ts'] = Float(lock_data['ts'])
|
49
|
+
lock_data['ini_ttl'] = Integer(lock_data['ini_ttl'])
|
50
|
+
lock_data['rem_ttl'] = ((pttl_cmd_res == -1) ? Infinity : pttl_cmd_res)
|
51
|
+
end
|
53
52
|
end
|
54
53
|
end
|
55
54
|
end
|
@@ -12,13 +12,13 @@ module RedisQueuedLocks::Acquier::QueueInfo
|
|
12
12
|
#
|
13
13
|
# @param redis_client [RedisClient]
|
14
14
|
# @param lock_name [String]
|
15
|
-
# @return [Hash<
|
15
|
+
# @return [Hash<String|Array<Hash<String,String|Numeric>>,NilClass]
|
16
16
|
# - `nil` is returned when lock queue does not exist;
|
17
17
|
# - result format: {
|
18
|
-
# lock_queue
|
18
|
+
# "lock_queue" => "rql:lock_queue:your_lock_name", # lock queue key in redis,
|
19
19
|
# queue: [
|
20
|
-
# { acq_id
|
21
|
-
# { acq_id
|
20
|
+
# { "acq_id" => "rql:acq:process_id/thread_id", "score" => 123 },
|
21
|
+
# { "acq_id" => "rql:acq:process_id/thread_id", "score" => 456 },
|
22
22
|
# ] # ordered set (by score) with information about an acquier and their position in queue
|
23
23
|
# }
|
24
24
|
#
|
@@ -38,8 +38,8 @@ module RedisQueuedLocks::Acquier::QueueInfo
|
|
38
38
|
if exists_cmd_res == 1
|
39
39
|
# NOTE: queue existed during the piepline invocation
|
40
40
|
{
|
41
|
-
lock_queue
|
42
|
-
queue
|
41
|
+
'lock_queue' => lock_key_queue,
|
42
|
+
'queue' => zrange_cmd_res.map { |val| { 'acq_id' => val[0], 'score' => val[1] } }
|
43
43
|
}
|
44
44
|
else
|
45
45
|
# NOTE: queue did not exist during the pipeline invocation
|
@@ -93,8 +93,9 @@ class RedisQueuedLocks::Client
|
|
93
93
|
# already obtained;
|
94
94
|
# - Should the logic exit immidietly after the first try if the lock was obtained
|
95
95
|
# by another process while the lock request queue was initially empty;
|
96
|
-
# @option
|
97
|
-
# - A custom metadata wich will be passed to the
|
96
|
+
# @option meta [NilClass,Hash<String|Symbol,Any>]
|
97
|
+
# - A custom metadata wich will be passed to the lock data in addition to the existing data;
|
98
|
+
# - Metadata can not contain reserved lock data keys;
|
98
99
|
# @option logger [::Logger,#debug]
|
99
100
|
# - Logger object used from the configuration layer (see config[:logger]);
|
100
101
|
# - See `RedisQueuedLocks::Logging::VoidLogger` for example;
|
@@ -102,6 +103,9 @@ class RedisQueuedLocks::Client
|
|
102
103
|
# - should be logged the each try of lock acquiring (a lot of logs can
|
103
104
|
# be generated depending on your retry configurations);
|
104
105
|
# - see `config[:log_lock_try]`;
|
106
|
+
# @option instrument [NilClass,Any]
|
107
|
+
# - Custom instrumentation data wich will be passed to the instrumenter's payload
|
108
|
+
# with :instrument key;
|
105
109
|
# @param block [Block]
|
106
110
|
# A block of code that should be executed after the successfully acquired lock.
|
107
111
|
# @return [RedisQueuedLocks::Data,Hash<Symbol,Any>,yield]
|
@@ -122,9 +126,10 @@ class RedisQueuedLocks::Client
|
|
122
126
|
raise_errors: false,
|
123
127
|
fail_fast: false,
|
124
128
|
identity: uniq_identity,
|
125
|
-
|
129
|
+
meta: nil,
|
126
130
|
logger: config[:logger],
|
127
131
|
log_lock_try: config[:log_lock_try],
|
132
|
+
instrument: nil,
|
128
133
|
&block
|
129
134
|
)
|
130
135
|
RedisQueuedLocks::Acquier::AcquireLock.acquire_lock(
|
@@ -145,9 +150,10 @@ class RedisQueuedLocks::Client
|
|
145
150
|
instrumenter: config[:instrumenter],
|
146
151
|
identity:,
|
147
152
|
fail_fast:,
|
148
|
-
|
153
|
+
meta:,
|
149
154
|
logger: config[:logger],
|
150
155
|
log_lock_try: config[:log_lock_try],
|
156
|
+
instrument:,
|
151
157
|
&block
|
152
158
|
)
|
153
159
|
end
|
@@ -167,9 +173,10 @@ class RedisQueuedLocks::Client
|
|
167
173
|
retry_jitter: config[:retry_jitter],
|
168
174
|
fail_fast: false,
|
169
175
|
identity: uniq_identity,
|
170
|
-
|
176
|
+
meta: nil,
|
171
177
|
logger: config[:logger],
|
172
178
|
log_lock_try: config[:log_lock_try],
|
179
|
+
instrument: nil,
|
173
180
|
&block
|
174
181
|
)
|
175
182
|
lock(
|
@@ -184,7 +191,8 @@ class RedisQueuedLocks::Client
|
|
184
191
|
raise_errors: true,
|
185
192
|
identity:,
|
186
193
|
fail_fast:,
|
187
|
-
|
194
|
+
meta:,
|
195
|
+
instrument:,
|
188
196
|
&block
|
189
197
|
)
|
190
198
|
end
|
@@ -224,7 +232,7 @@ class RedisQueuedLocks::Client
|
|
224
232
|
end
|
225
233
|
|
226
234
|
# @param lock_name [String]
|
227
|
-
# @return [Hash,NilClass]
|
235
|
+
# @return [Hash<String,String|Numeric>,NilClass]
|
228
236
|
#
|
229
237
|
# @api public
|
230
238
|
# @since 0.1.0
|
@@ -233,7 +241,7 @@ class RedisQueuedLocks::Client
|
|
233
241
|
end
|
234
242
|
|
235
243
|
# @param lock_name [String]
|
236
|
-
# @return [Hash,NilClass]
|
244
|
+
# @return [Hash<String|Array<Hash<String,String|Numeric>>,NilClass]
|
237
245
|
#
|
238
246
|
# @api public
|
239
247
|
# @since 0.1.0
|
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: 0.0.
|
4
|
+
version: 0.0.32
|
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-03-
|
11
|
+
date: 2024-03-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis-client
|
@@ -107,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
107
|
- !ruby/object:Gem::Version
|
108
108
|
version: '0'
|
109
109
|
requirements: []
|
110
|
-
rubygems_version: 3.
|
110
|
+
rubygems_version: 3.5.1
|
111
111
|
signing_key:
|
112
112
|
specification_version: 4
|
113
113
|
summary: Queued distributed locks based on Redis.
|