redis_queued_locks 0.0.18 → 0.0.19

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0993079d1a7cca97094c741d65c4ef1e8a5694184212b6597960e0b3c91d83cb'
4
- data.tar.gz: 22535e254fa22db6bfb0225f391e3d4606ad680bb401034fcbdfcd8e93a1fc5c
3
+ metadata.gz: c77f863ddb9f33c75a636ea12281ce1f4df1215d50f43b113b5be5f79b679526
4
+ data.tar.gz: 9585690846e55b141e089d26ac160f6481297cfa6f43d21df1403411903221be
5
5
  SHA512:
6
- metadata.gz: 7db77251aefc59a83a9727d756774f5eb6b30a156fd058d69ec5170d252cc8fb875b2f213da2e15a4bdf9f5565565aa5ca699545ac0a83dcbc333fbed8c7aec1
7
- data.tar.gz: 659c47a6aaa421ade9c7ffaea000a7133c1ba72f5ab0a2e66bc56f5ad72f84f4d9525fc86024e5d52b8196a6dfc7b0a714100462915a91405c97c3b3d77d3e26
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/expire'
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 Expire
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
- with_timeout(timeout, lock_key, raise_errors, on_timeout: acq_dequeue) do
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
- yield_with_expire(redis, lock_key, &block)
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 with_timeout(timeout, lock_key, raise_errors, on_timeout: nil, &block)
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:,
@@ -20,4 +20,8 @@ module RedisQueuedLocks
20
20
  # @api public
21
21
  # @since 0.1.0
22
22
  LockAcquiermentRetryLimitError = Class.new(Error)
23
+
24
+ # @api pulic
25
+ # @since 0.1.0
26
+ TimedLockTimeoutError = Class.new(Error)
23
27
  end
@@ -5,6 +5,6 @@ module RedisQueuedLocks
5
5
  #
6
6
  # @api public
7
7
  # @since 0.0.1
8
- # @version 0.0.18
9
- VERSION = '0.0.18'
8
+ # @version 0.0.19
9
+ VERSION = '0.0.19'
10
10
  end
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.18
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-04 00:00:00.000000000 Z
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