redis_queued_locks 0.0.16 → 0.0.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +103 -2
- data/lib/redis_queued_locks/acquier/release.rb +2 -0
- data/lib/redis_queued_locks/acquier.rb +60 -1
- data/lib/redis_queued_locks/client.rb +28 -0
- data/lib/redis_queued_locks/resource.rb +6 -0
- data/lib/redis_queued_locks/version.rb +2 -2
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb745a97296f4661f7a68d7719d7bdb894521348d6aa25b92b23b4fcffce56cd
|
4
|
+
data.tar.gz: e12566b1c653ad97bf973887d4511482c628d8ec27fd265901d1d4bfba9c112b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3e6f4c421c8e6fb9b3933c01ebcd23d5762f0bdb0581333e2d85ab478a8002d8bce360bfabaab29d819c92a4f148e6562d0fa426e5999b0fc2d1c9b59f3eaa7
|
7
|
+
data.tar.gz: 42a5800757191ea80797c7462b765c5dd4187771ce73c6c9af70f6653dea5599710d8569b5a2fc1a0c30cb0b3483abfac557bd888a7f4bcbde4ac4a7de308021
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.0.17] - 2024-02-29
|
4
|
+
### Added
|
5
|
+
- `RedisQueuedLocks::Client#locks` - list of obtained locks;
|
6
|
+
- `RedisQueuedLocks::Client#queues` - list of existing lock request queus;
|
7
|
+
- `RedisQueuedLocks::Client#keys` - get list of taken locks and queues;
|
8
|
+
|
3
9
|
## [0.0.16] - 2024-02-29
|
4
10
|
### Fixed
|
5
11
|
- Execution delay formula returns the value "in seconds" (should be "in milliseconds");
|
data/README.md
CHANGED
@@ -21,6 +21,10 @@ Each lock request is put into the request queue and processed in order of their
|
|
21
21
|
- [queued?](#queued)
|
22
22
|
- [unlock](#unlock---release-a-lock)
|
23
23
|
- [clear_locks](#clear_locks---release-all-locks-and-lock-queues)
|
24
|
+
- [extend_lock_ttl](#extend_lock_ttl)
|
25
|
+
- [locks](#locks---get-list-of-obtained-locks)
|
26
|
+
- [queues](#queues---get-list-of-lock-request-queues)
|
27
|
+
- [keys](#keys---get-list-of-taken-locks-and-queues)
|
24
28
|
- [Instrumentation](#instrumentation)
|
25
29
|
- [Instrumentation Events](#instrumentation-events)
|
26
30
|
- [Roadmap](#roadmap)
|
@@ -104,10 +108,15 @@ clinet = RedisQueuedLocks::Client.new(redis_client) do |config|
|
|
104
108
|
config.default_queue_ttl = 15
|
105
109
|
|
106
110
|
# (default: 100)
|
107
|
-
# - how many items will be released at a time in RedisQueuedLocks::Client#clear_locks logic;
|
108
|
-
# - affects the performancs
|
111
|
+
# - how many items will be released at a time in RedisQueuedLocks::Client#clear_locks logic (uses SCAN);
|
112
|
+
# - affects the performancs of your Redis and Ruby Application (configure thoughtfully);
|
109
113
|
config.lock_release_batch_size = 100
|
110
114
|
|
115
|
+
# (default: 500)
|
116
|
+
# - how many items should be extracted from redis during the #locks, #queues and #keys operations (uses SCAN);
|
117
|
+
# - affects the performance of your Redis and Ruby Application (configure thoughtfully;)
|
118
|
+
config.key_extraction_batch_size = 500
|
119
|
+
|
111
120
|
# (default: RedisQueuedLocks::Instrument::VoidNotifier)
|
112
121
|
# - instrumentation layer;
|
113
122
|
# - you can provde your own instrumenter with `#notify(event, payload = {})`
|
@@ -138,6 +147,10 @@ end
|
|
138
147
|
- [queued?](#queued)
|
139
148
|
- [unlock](#unlock---release-a-lock)
|
140
149
|
- [clear_locks](#clear_locks---release-all-locks-and-lock-queues)
|
150
|
+
- [extend_lock_ttl](#extend_lock_ttl)
|
151
|
+
- [locks](#locks---get-list-of-obtained-locks)
|
152
|
+
- [queues](#queues---get-list-of-lock-request-queues)
|
153
|
+
- [keys](#keys---get-list-of-taken-locks-and-queues)
|
141
154
|
|
142
155
|
---
|
143
156
|
|
@@ -393,6 +406,94 @@ Return:
|
|
393
406
|
|
394
407
|
---
|
395
408
|
|
409
|
+
#### #extend_lock_ttl
|
410
|
+
|
411
|
+
- soon
|
412
|
+
|
413
|
+
---
|
414
|
+
|
415
|
+
#### #locks - get list of obtained locks
|
416
|
+
|
417
|
+
- uses redis `SCAN` under the hood;
|
418
|
+
- accepts `scan_size:`/`Integer` option (`config[:key_extraction_batch_size]` by default);
|
419
|
+
- returns `Set<String>`
|
420
|
+
|
421
|
+
```ruby
|
422
|
+
rql.locks # or rql.locks(scan_size: 123)
|
423
|
+
|
424
|
+
=>
|
425
|
+
#<Set:
|
426
|
+
{"rql:lock:locklock75",
|
427
|
+
"rql:lock:locklock9",
|
428
|
+
"rql:lock:locklock108",
|
429
|
+
"rql:lock:locklock7",
|
430
|
+
"rql:lock:locklock48",
|
431
|
+
"rql:lock:locklock104",
|
432
|
+
"rql:lock:locklock13",
|
433
|
+
"rql:lock:locklock62",
|
434
|
+
"rql:lock:locklock80",
|
435
|
+
"rql:lock:locklock28",
|
436
|
+
...}>
|
437
|
+
```
|
438
|
+
|
439
|
+
---
|
440
|
+
|
441
|
+
#### #queues - get list of lock request queues
|
442
|
+
|
443
|
+
- uses redis `SCAN` under the hood;
|
444
|
+
- accepts `scan_size:`/`Integer` option (`config[:key_extraction_batch_size]` by default);
|
445
|
+
- returns `Set<String>`
|
446
|
+
|
447
|
+
```ruby
|
448
|
+
rql.queues # or rql.queues(scan_size: 123)
|
449
|
+
|
450
|
+
=>
|
451
|
+
#<Set:
|
452
|
+
{"rql:lock_queue:locklock75",
|
453
|
+
"rql:lock_queue:locklock9",
|
454
|
+
"rql:lock_queue:locklock108",
|
455
|
+
"rql:lock_queue:locklock7",
|
456
|
+
"rql:lock_queue:locklock48",
|
457
|
+
"rql:lock_queue:locklock104",
|
458
|
+
"rql:lock_queue:locklock13",
|
459
|
+
"rql:lock_queue:locklock62",
|
460
|
+
"rql:lock_queue:locklock80",
|
461
|
+
"rql:lock_queue:locklock28",
|
462
|
+
...}>
|
463
|
+
```
|
464
|
+
|
465
|
+
---
|
466
|
+
|
467
|
+
#### #keys - get list of taken locks and queues
|
468
|
+
|
469
|
+
- uses redis `SCAN` under the hood;
|
470
|
+
- accepts `scan_size:`/`Integer` option (`config[:key_extraction_batch_size]` by default);
|
471
|
+
- returns `Set<String>`
|
472
|
+
|
473
|
+
```ruby
|
474
|
+
rql.keys # or rql.keys(scan_size: 123)
|
475
|
+
|
476
|
+
=>
|
477
|
+
#<Set:
|
478
|
+
{"rql:lock_queue:locklock75",
|
479
|
+
"rql:lock_queue:locklock9",
|
480
|
+
"rql:lock:locklock9",
|
481
|
+
"rql:lock_queue:locklock108",
|
482
|
+
"rql:lock_queue:locklock7",
|
483
|
+
"rql:lock:locklock7",
|
484
|
+
"rql:lock_queue:locklock48",
|
485
|
+
"rql:lock_queue:locklock104",
|
486
|
+
"rql:lock:locklock104",
|
487
|
+
"rql:lock_queue:locklock13",
|
488
|
+
"rql:lock_queue:locklock62",
|
489
|
+
"rql:lock_queue:locklock80",
|
490
|
+
"rql:lock:locklock80",
|
491
|
+
"rql:lock_queue:locklock28",
|
492
|
+
...}>
|
493
|
+
```
|
494
|
+
|
495
|
+
---
|
496
|
+
|
396
497
|
## Instrumentation
|
397
498
|
|
398
499
|
An instrumentation layer is incapsulated in `instrumenter` object stored in [config](#configuration) (`RedisQueuedLocks::Client#config[:instrumenter]`).
|
@@ -37,6 +37,7 @@ module RedisQueuedLocks::Acquier::Release
|
|
37
37
|
RedisQueuedLocks::Resource::LOCK_QUEUE_PATTERN,
|
38
38
|
count: batch_size
|
39
39
|
) do |lock_queue|
|
40
|
+
# TODO: reduce unnecessary iterations
|
40
41
|
pipeline.call('ZREMRANGEBYSCORE', lock_queue, '-inf', '+inf')
|
41
42
|
pipeline.call('EXPIRE', RedisQueuedLocks::Resource.lock_key_from_queue(lock_queue), '0')
|
42
43
|
end
|
@@ -47,6 +48,7 @@ module RedisQueuedLocks::Acquier::Release
|
|
47
48
|
RedisQueuedLocks::Resource::LOCK_PATTERN,
|
48
49
|
count: batch_size
|
49
50
|
) do |lock_key|
|
51
|
+
# TODO: reduce unnecessary iterations
|
50
52
|
pipeline.call('EXPIRE', lock_key, '0')
|
51
53
|
end
|
52
54
|
end
|
@@ -437,7 +437,66 @@ module RedisQueuedLocks::Acquier
|
|
437
437
|
#
|
438
438
|
# @api private
|
439
439
|
# @since 0.1.0
|
440
|
-
def extend_lock_ttl(redis_client, lock_name, milliseconds)
|
440
|
+
def extend_lock_ttl(redis_client, lock_name, milliseconds)
|
441
|
+
# TODO: realize
|
442
|
+
end
|
443
|
+
|
444
|
+
# @param redis_client [RedisClient]
|
445
|
+
# @option scan_size [Integer]
|
446
|
+
# @return [Set<String>]
|
447
|
+
#
|
448
|
+
# @api private
|
449
|
+
# @since 0.1.0
|
450
|
+
def locks(redis_client, scan_size:)
|
451
|
+
Set.new.tap do |lock_keys|
|
452
|
+
redis_client.scan(
|
453
|
+
'MATCH',
|
454
|
+
RedisQueuedLocks::Resource::LOCK_PATTERN,
|
455
|
+
count: scan_size
|
456
|
+
) do |lock_key|
|
457
|
+
# TODO: reduce unnecessary iterations
|
458
|
+
lock_keys.add(lock_key)
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
# @param redis_client [RedisClient]
|
464
|
+
# @param scan_size [Integer]
|
465
|
+
# @return [Set<String>]
|
466
|
+
#
|
467
|
+
# @api private
|
468
|
+
# @since 0.1.0
|
469
|
+
def queues(redis_client, scan_size:)
|
470
|
+
Set.new.tap do |lock_queues|
|
471
|
+
redis_client.scan(
|
472
|
+
'MATCH',
|
473
|
+
RedisQueuedLocks::Resource::LOCK_QUEUE_PATTERN,
|
474
|
+
count: scan_size
|
475
|
+
) do |lock_queue|
|
476
|
+
# TODO: reduce unnecessary iterations
|
477
|
+
lock_queues.add(lock_queue)
|
478
|
+
end
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
# @param redis_client [RedisClient]
|
483
|
+
# @option scan_size [Integer]
|
484
|
+
# @return [Array<String>]
|
485
|
+
#
|
486
|
+
# @api private
|
487
|
+
# @since 0.1.0
|
488
|
+
def keys(redis_client, scan_size:)
|
489
|
+
Set.new.tap do |keys|
|
490
|
+
redis_client.scan(
|
491
|
+
'MATCH',
|
492
|
+
RedisQueuedLocks::Resource::KEY_PATTERN,
|
493
|
+
count: scan_size
|
494
|
+
) do |key|
|
495
|
+
# TODO: reduce unnecessary iterations
|
496
|
+
keys.add(key)
|
497
|
+
end
|
498
|
+
end
|
499
|
+
end
|
441
500
|
|
442
501
|
private
|
443
502
|
|
@@ -15,6 +15,7 @@ class RedisQueuedLocks::Client
|
|
15
15
|
setting :default_lock_ttl, 5_000 # NOTE: milliseconds
|
16
16
|
setting :default_queue_ttl, 15 # NOTE: seconds
|
17
17
|
setting :lock_release_batch_size, 100
|
18
|
+
setting :key_extraction_batch_size, 500
|
18
19
|
setting :instrumenter, RedisQueuedLocks::Instrument::VoidNotifier
|
19
20
|
setting :uniq_identifier, -> { RedisQueuedLocks::Resource.calc_uniq_identity }
|
20
21
|
|
@@ -225,5 +226,32 @@ class RedisQueuedLocks::Client
|
|
225
226
|
def clear_locks(batch_size: config[:lock_release_batch_size])
|
226
227
|
RedisQueuedLocks::Acquier.release_all_locks!(redis_client, batch_size, config[:instrumenter])
|
227
228
|
end
|
229
|
+
|
230
|
+
# @option scan_size [Integer]
|
231
|
+
# @return [Set<String>]
|
232
|
+
#
|
233
|
+
# @api public
|
234
|
+
# @since 0.1.0
|
235
|
+
def locks(scan_size: config[:key_extraction_batch_size])
|
236
|
+
RedisQueuedLocks::Acquier.locks(redis_client, scan_size:)
|
237
|
+
end
|
238
|
+
|
239
|
+
# @option scan_size [Integer]
|
240
|
+
# @return [Set<String>]
|
241
|
+
#
|
242
|
+
# @api public
|
243
|
+
# @since 0.1.0
|
244
|
+
def queues(scan_size: config[:key_extraction_batch_size])
|
245
|
+
RedisQueuedLocks::Acquier.queues(redis_client, scan_size:)
|
246
|
+
end
|
247
|
+
|
248
|
+
# @option scan_size [Integer]
|
249
|
+
# @return [Set<String>]
|
250
|
+
#
|
251
|
+
# @api public
|
252
|
+
# @since 0.1.0
|
253
|
+
def keys(scan_size: config[:key_extraction_batch_size])
|
254
|
+
RedisQueuedLocks::Acquier.keys(redis_client, scan_size:)
|
255
|
+
end
|
228
256
|
end
|
229
257
|
# rubocop:enable Metrics/ClassLength
|