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 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