redis_queued_locks 0.0.18 → 0.0.19
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 +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +3 -0
- data/lib/redis_queued_locks/acquier/yield_expire.rb +46 -0
- data/lib/redis_queued_locks/acquier.rb +11 -5
- data/lib/redis_queued_locks/client.rb +6 -0
- data/lib/redis_queued_locks/errors.rb +4 -0
- data/lib/redis_queued_locks/version.rb +2 -2
- metadata +3 -3
- data/lib/redis_queued_locks/acquier/expire.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c77f863ddb9f33c75a636ea12281ce1f4df1215d50f43b113b5be5f79b679526
|
4
|
+
data.tar.gz: 9585690846e55b141e089d26ac160f6481297cfa6f43d21df1403411903221be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e132a1464d92aa59539d5489d5b7d777399de6c38f313cbad063b819e0e32503591532eb010f5c6b87da41096172e9dde8f5fa2fc84623ca2256b84cd3fa98d
|
7
|
+
data.tar.gz: ea8dc9808a5c16697e5606ce8394c987ceb8df4f561fbf06250bd7669188665f56825a582e9c82240a52b6376767eedda9afeed588f960498fb32070466c512c
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.0.19] - 2024-03-12
|
4
|
+
### Added
|
5
|
+
- An ability to set the invocation time period to the block of code invoked under
|
6
|
+
the obtained lock;
|
7
|
+
|
3
8
|
## [0.0.18] - 2024-03-04
|
4
9
|
### Changed
|
5
10
|
- Semantic results for methods returning `{ ok: true/false, result: Any }` hash objects.
|
data/README.md
CHANGED
@@ -167,6 +167,7 @@ def lock(
|
|
167
167
|
ttl: config[:default_lock_ttl],
|
168
168
|
queue_ttl: config[:default_queue_ttl],
|
169
169
|
timeout: config[:try_to_lock_timeout],
|
170
|
+
timed: false,
|
170
171
|
retry_count: config[:retry_count],
|
171
172
|
retry_delay: config[:retry_delay],
|
172
173
|
retry_jitter: config[:retry_jitter],
|
@@ -185,6 +186,8 @@ def lock(
|
|
185
186
|
- Lifetime of the acuier's lock request. In seconds.
|
186
187
|
- `timeout` - `[Integer,NilClass]`
|
187
188
|
- Time period whe should try to acquire the lock (in seconds). Nil means "without timeout".
|
189
|
+
- `timed` - `[Boolean]`
|
190
|
+
- Limit the invocation time period of the passed block of code by the lock's TTL.
|
188
191
|
- `retry_count` - `[Integer,NilClass]`
|
189
192
|
- How many times we should try to acquire a lock. Nil means "infinite retries".
|
190
193
|
- `retry_delay` - `[Integer]`
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
module RedisQueuedLocks::Acquier::YieldExpire
|
6
|
+
# @param redis [RedisClient] Redis connection manager.
|
7
|
+
# @param lock_key [String] Lock key to be expired.
|
8
|
+
# @param timed [Boolean] Should the lock be wrapped by Tiemlout with with lock's ttl
|
9
|
+
# @param ttl_shift [Float] Lock's TTL shifting. Should affect block's ttl. In millisecodns.
|
10
|
+
# @param ttl [Integer,NilClass] Lock's time to live (in ms). Nil means "without timeout".
|
11
|
+
# @param block [Block] Custom logic that should be invoked unter the obtained lock.
|
12
|
+
# @return [Any,NilClass] nil is returned no block parametr is provided.
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
# @since 0.1.0
|
16
|
+
def yield_with_expire(redis, lock_key, timed, ttl_shift, ttl, &block)
|
17
|
+
if block_given?
|
18
|
+
if timed && ttl != nil
|
19
|
+
timeout = ((ttl - ttl_shift) / 1000.0).yield_self { |time| (time < 0) ? 0.0 : time }
|
20
|
+
yield_with_timeout(timeout, lock_key, ttl, &block)
|
21
|
+
else
|
22
|
+
yield
|
23
|
+
end
|
24
|
+
end
|
25
|
+
ensure
|
26
|
+
redis.call('EXPIRE', lock_key, '0')
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# @param timeout [Float]
|
32
|
+
# @parma lock_key [String]
|
33
|
+
# @param lock_ttl [Integer,NilClass]
|
34
|
+
# @param block [Blcok]
|
35
|
+
# @return [Any]
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
# @since 0.1.0
|
39
|
+
def yield_with_timeout(timeout, lock_key, lock_ttl, &block)
|
40
|
+
::Timeout.timeout(timeout, &block)
|
41
|
+
rescue ::Timeout::Error
|
42
|
+
raise(RedisQueuedLocks::TimedLockTimeoutError, <<~ERROR_MESSAGE)
|
43
|
+
Passed <timed> block of code exceeded the lock TTL (lock: "#{lock_key}", ttl: #{lock_ttl})
|
44
|
+
ERROR_MESSAGE
|
45
|
+
end
|
46
|
+
end
|
@@ -6,7 +6,7 @@
|
|
6
6
|
module RedisQueuedLocks::Acquier
|
7
7
|
require_relative 'acquier/try'
|
8
8
|
require_relative 'acquier/delay'
|
9
|
-
require_relative 'acquier/
|
9
|
+
require_relative 'acquier/yield_expire'
|
10
10
|
require_relative 'acquier/release'
|
11
11
|
|
12
12
|
# @since 0.1.0
|
@@ -14,7 +14,7 @@ module RedisQueuedLocks::Acquier
|
|
14
14
|
# @since 0.1.0
|
15
15
|
extend Delay
|
16
16
|
# @since 0.1.0
|
17
|
-
extend
|
17
|
+
extend YieldExpire
|
18
18
|
# @since 0.1.0
|
19
19
|
extend Release
|
20
20
|
|
@@ -44,6 +44,8 @@ module RedisQueuedLocks::Acquier
|
|
44
44
|
# Lifetime of the acuier's lock request. In seconds.
|
45
45
|
# @option timeout [Integer]
|
46
46
|
# Time period whe should try to acquire the lock (in seconds).
|
47
|
+
# @option timed [Boolean]
|
48
|
+
# Limit the invocation time period of the passed block of code by the lock's TTL.
|
47
49
|
# @option retry_count [Integer,NilClass]
|
48
50
|
# How many times we should try to acquire a lock. Nil means "infinite retries".
|
49
51
|
# @option retry_delay [Integer]
|
@@ -80,6 +82,7 @@ module RedisQueuedLocks::Acquier
|
|
80
82
|
ttl:,
|
81
83
|
queue_ttl:,
|
82
84
|
timeout:,
|
85
|
+
timed:,
|
83
86
|
retry_count:,
|
84
87
|
retry_delay:,
|
85
88
|
retry_jitter:,
|
@@ -119,7 +122,7 @@ module RedisQueuedLocks::Acquier
|
|
119
122
|
acq_dequeue = -> { dequeue_from_lock_queue(redis, lock_key_queue, acquier_id) }
|
120
123
|
|
121
124
|
# Step 2: try to lock with timeout
|
122
|
-
|
125
|
+
with_acq_timeout(timeout, lock_key, raise_errors, on_timeout: acq_dequeue) do
|
123
126
|
acq_start_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
124
127
|
|
125
128
|
# Step 2.1: caclically try to obtain the lock
|
@@ -140,6 +143,7 @@ module RedisQueuedLocks::Acquier
|
|
140
143
|
|
141
144
|
# Step X: save the intermediate results to the result observer
|
142
145
|
acq_process[:result] = result
|
146
|
+
acq_process[:acq_end_time] = acq_end_time
|
143
147
|
|
144
148
|
# Step 2.1: analyze an acquirement attempt
|
145
149
|
if ok
|
@@ -212,7 +216,9 @@ module RedisQueuedLocks::Acquier
|
|
212
216
|
# Step 3.a: acquired successfully => run logic or return the result of acquirement
|
213
217
|
if block_given?
|
214
218
|
begin
|
215
|
-
|
219
|
+
yield_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
220
|
+
ttl_shift = ((yield_time - acq_process[:acq_end_time]) * 1000).ceil(2)
|
221
|
+
yield_with_expire(redis, lock_key, timed, ttl_shift, ttl, &block)
|
216
222
|
ensure
|
217
223
|
acq_process[:rel_time] = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
218
224
|
acq_process[:hold_time] = (
|
@@ -526,7 +532,7 @@ module RedisQueuedLocks::Acquier
|
|
526
532
|
#
|
527
533
|
# @api private
|
528
534
|
# @since 0.1.0
|
529
|
-
def
|
535
|
+
def with_acq_timeout(timeout, lock_key, raise_errors, on_timeout: nil, &block)
|
530
536
|
::Timeout.timeout(timeout, &block)
|
531
537
|
rescue ::Timeout::Error
|
532
538
|
on_timeout.call unless on_timeout == nil
|
@@ -71,6 +71,8 @@ class RedisQueuedLocks::Client
|
|
71
71
|
# Lifetime of the acuier's lock request. In seconds.
|
72
72
|
# @option timeout [Integer,NilClass]
|
73
73
|
# Time period whe should try to acquire the lock (in seconds). Nil means "without timeout".
|
74
|
+
# @option timed [Boolean]
|
75
|
+
# Limit the invocation time period of the passed block of code by the lock's TTL.
|
74
76
|
# @option retry_count [Integer,NilClass]
|
75
77
|
# How many times we should try to acquire a lock. Nil means "infinite retries".
|
76
78
|
# @option retry_delay [Integer]
|
@@ -103,6 +105,7 @@ class RedisQueuedLocks::Client
|
|
103
105
|
ttl: config[:default_lock_ttl],
|
104
106
|
queue_ttl: config[:default_queue_ttl],
|
105
107
|
timeout: config[:try_to_lock_timeout],
|
108
|
+
timed: false,
|
106
109
|
retry_count: config[:retry_count],
|
107
110
|
retry_delay: config[:retry_delay],
|
108
111
|
retry_jitter: config[:retry_jitter],
|
@@ -121,6 +124,7 @@ class RedisQueuedLocks::Client
|
|
121
124
|
ttl:,
|
122
125
|
queue_ttl:,
|
123
126
|
timeout:,
|
127
|
+
timed:,
|
124
128
|
retry_count:,
|
125
129
|
retry_delay:,
|
126
130
|
retry_jitter:,
|
@@ -141,6 +145,7 @@ class RedisQueuedLocks::Client
|
|
141
145
|
ttl: config[:default_lock_ttl],
|
142
146
|
queue_ttl: config[:default_queue_ttl],
|
143
147
|
timeout: config[:try_to_lock_timeout],
|
148
|
+
timed: false,
|
144
149
|
retry_count: config[:retry_count],
|
145
150
|
retry_delay: config[:retry_delay],
|
146
151
|
retry_jitter: config[:retry_jitter],
|
@@ -153,6 +158,7 @@ class RedisQueuedLocks::Client
|
|
153
158
|
ttl:,
|
154
159
|
queue_ttl:,
|
155
160
|
timeout:,
|
161
|
+
timed:,
|
156
162
|
retry_count:,
|
157
163
|
retry_delay:,
|
158
164
|
retry_jitter:,
|
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.19
|
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-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis-client
|
@@ -57,9 +57,9 @@ files:
|
|
57
57
|
- lib/redis_queued_locks.rb
|
58
58
|
- lib/redis_queued_locks/acquier.rb
|
59
59
|
- lib/redis_queued_locks/acquier/delay.rb
|
60
|
-
- lib/redis_queued_locks/acquier/expire.rb
|
61
60
|
- lib/redis_queued_locks/acquier/release.rb
|
62
61
|
- lib/redis_queued_locks/acquier/try.rb
|
62
|
+
- lib/redis_queued_locks/acquier/yield_expire.rb
|
63
63
|
- lib/redis_queued_locks/client.rb
|
64
64
|
- lib/redis_queued_locks/data.rb
|
65
65
|
- lib/redis_queued_locks/debugger.rb
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# @api private
|
4
|
-
# @since 0.1.0
|
5
|
-
module RedisQueuedLocks::Acquier::Expire
|
6
|
-
# @param redis [RedisClient] Redis connection manager.
|
7
|
-
# @param lock_key [String] Lock key to be expired.
|
8
|
-
# @param block [Block] Custom logic that should be invoked unter the obtained lock.
|
9
|
-
# @return [Any,NilClass] nil is returned no block parametr is provided.
|
10
|
-
#
|
11
|
-
# @api private
|
12
|
-
# @since 0.1.0
|
13
|
-
def yield_with_expire(redis, lock_key, &block)
|
14
|
-
yield if block_given?
|
15
|
-
ensure
|
16
|
-
redis.call('EXPIRE', lock_key, '0')
|
17
|
-
end
|
18
|
-
end
|