redis_queued_locks 0.0.5 → 0.0.7

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: 1044ea4b8236b241132017ea9b9f2f8ac280c584be1158a9e7b52b15aa58d4ef
4
- data.tar.gz: 5e6dc2141b05055f3641d88c9c181521ed6ad94100f6007573628e6aef7cee17
3
+ metadata.gz: 56120a88eb6ffa4f377c014b8619cdcd227ac0efaab1c6ec6495042c74739a63
4
+ data.tar.gz: d1e7240b5ca0c8a18842cd609b1e9280813a0a51a62d2ed9bcacdb66d707801f
5
5
  SHA512:
6
- metadata.gz: 8d8c0ac83545d663f0d558dc258364348a100e34c9636bf9663d8c021154c38c660ee626019f08bc5607c4ce01fc731a49c1fae3f5dc6e28d3a5d2ea41292d02
7
- data.tar.gz: 1bbc2cfc740ff6eb3fa6e458dc5ed9dd4509885427eaf7e5eb8c2e74a605652dc9c39586d7282442befb1f199d0b84ff3ac573dfa43bfcc86bcb117f165e70ca
6
+ metadata.gz: f3df6ebf409fa4d97ebe51632832d6c9c64eb03a4102d68e6951def7a3d351c62e86e63014b8cc1d5c6ea4c5cd6bf9bdf5595ebdb2a3334550e7a27f2f6b0bcd
7
+ data.tar.gz: 6e512298fb8be556e5370574e87529b936670bec1b13250233c6ce08d9feb4c8032b1b07e90a514ff4d4687e01391424be5b546a124119c7937492baa7ef87ee
data/CHANGELOG.md CHANGED
@@ -1,7 +1,18 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.0.7] - 2024-02-27
4
+ ### Changed
5
+ - Minor documentation updates;
6
+
7
+ ## [0.0.6] - 2024-02-27
8
+ ### Changed
9
+ - Major documentation updates;
10
+ - `RedisQueuedLock#release_lock!` now returns detaield semantic result;
11
+ - `RediSQueuedLock#release_all_locks!` now returns detailed semantic result;
12
+
3
13
  ## [0.0.5] - 2024-02-26
4
- - Minor update with documentation and configuration updates inside.
14
+ ### Changed
15
+ - Minor gem update with documentation and configuration updates inside.
5
16
 
6
17
  ## [0.0.4] - 2024-02-26
7
18
  ### Changed
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # RedisQueuedLocks
2
2
 
3
- Distributed lock implementation with "lock acquisition queue" capabilities based on the Redis Database.
3
+ Distributed locks with "lock acquisition queue" capabilities based on the Redis Database.
4
+
4
5
  Each lock request is put into a request queue and processed in order of their priority (FIFO).
5
6
 
6
7
  ---
@@ -18,7 +19,7 @@ Each lock request is put into a request queue and processed in order of their pr
18
19
  - [clear_locks](#clear_locks---release-all-locks-and-lock-queues)
19
20
  - [Instrumentation](#instrumentation)
20
21
  - [Instrumentation Events](#instrumentation-events)
21
- - [TODO](#todo)
22
+ - [Todo](#todo)
22
23
  - [Contributing](#contributing)
23
24
  - [License](#license)
24
25
  - [Authors](#authors)
@@ -65,6 +66,7 @@ rq_lock_client = RedisQueuedLocks::Client.new(redis_client) do |config|
65
66
  end
66
67
 
67
68
  # Step 3: start to work with locks :)
69
+ rq_lock_client.lock("some-lock") { puts "Hello, lock!" }
68
70
  ```
69
71
 
70
72
  ---
@@ -127,7 +129,7 @@ end
127
129
 
128
130
  ---
129
131
 
130
- #### lock - obtain a lock
132
+ #### #lock - obtain a lock
131
133
 
132
134
  ```ruby
133
135
  def lock(
@@ -166,9 +168,11 @@ def lock(
166
168
  - `instrumenter` - `[#notify]`
167
169
  - See RedisQueuedLocks::Instrument::ActiveSupport for example.
168
170
  - `raise_errors` - `[Boolean]`
169
- - Raise errors on library-related limits such as timeout or failed lock obtain.
171
+ - Raise errors on library-related limits such as timeout or retry count limit.
170
172
  - `block` - `[Block]`
171
173
  - A block of code that should be executed after the successfully acquired lock.
174
+ - If block is **passed** the obtained lock will be released after the block execution or it's ttl (what will happen first);
175
+ - If block is **not passed** the obtained lock will be released after it's ttl;
172
176
 
173
177
  Return value:
174
178
  - `[Hash<Symbol,Any>]` Format: `{ ok: true/false, result: Symbol/Hash }`;
@@ -186,20 +190,18 @@ Return value:
186
190
  ```
187
191
  - for failed lock obtaining:
188
192
  ```ruby
189
- { ok: false, result: :acquier_is_not_first_in_queue }
190
- { ok: false, result: :lock_is_still_acquired }
191
- { ok: false, result: :lock_is_acquired_during_acquire_race }
193
+ { ok: false, result: :timeout_reached }
194
+ { ok: false, result: :retry_count_reached }
192
195
  { ok: false, result: :unknown }
193
196
  ```
194
197
 
195
-
196
198
  ---
197
199
 
198
200
  #### #lock! - exceptional lock obtaining
199
201
 
200
- - fails when:
201
- - `timeout` limit reached before lock is obtained;
202
- - `retry_count` limit reached before lock is obtained;
202
+ - fails when (and with):
203
+ - (`RedisQueuedLocks::LockAcquiermentTimeoutError`) `timeout` limit reached before lock is obtained;
204
+ - (`RedisQueuedLocks::LockAcquiermentRetryLimitError`) `retry_count` limit reached before lock is obtained;
203
205
 
204
206
  ```ruby
205
207
  def lock!(
@@ -233,7 +235,18 @@ def unlock(lock_name)
233
235
  - the lock name that should be released.
234
236
 
235
237
  Return:
236
- - `[Hash<Symbol,Any>]` - Format: `{ ok: true/false, result: Symbol/Hash }`;
238
+ - `[Hash<Symbol,Any>]` - Format: `{ ok: true/false, result: Hash<Symbol,Numeric|String> }`;
239
+
240
+ ```ruby
241
+ {
242
+ ok: true,
243
+ result: {
244
+ rel_time: 0.02, # time spent to lock release (in seconds)
245
+ rel_key: "rql:lock:your_lock_name", # released lock key
246
+ rel_queue: "rql:lock_queue:your_lock_name" # released lock key queue
247
+ }
248
+ }
249
+ ```
237
250
 
238
251
  ---
239
252
 
@@ -250,15 +263,25 @@ def clear_locks(batch_size: config[:lock_release_batch_size])
250
263
  - batch of cleared locks and lock queus unde the one pipelined redis command;
251
264
 
252
265
  Return:
253
- - `[Hash<Symbol,Any>]` - Format: `{ ok: true/false, result: Symbol/Hash }`;
266
+ - `[Hash<Symbol,Any>]` - Format: `{ ok: true/false, result: Hash<Symbol,Numeric> }`;
267
+
268
+ ```ruby
269
+ {
270
+ ok: true,
271
+ result: {
272
+ rel_time: 3.07, # time spent to release all locks and related lock queues
273
+ rel_key_cnt: 100_500 # released redis keys (released locks + released lock queues)
274
+ }
275
+ }
276
+ ```
254
277
 
255
278
  ---
256
279
 
257
280
  ## Instrumentation
258
281
 
259
- An instrumentation layer is incapsulated in `instrumenter` object stored in configurations.
282
+ An instrumentation layer is incapsulated in `instrumenter` object stored in [config](#configuration) (`RedisQueuedLocks::Client#config[:instrumenter]`).
260
283
 
261
- Instrumenter object should provide `notify(event, payload)` method with following signarue:
284
+ Instrumenter object should provide `notify(event, payload)` method with the following signarue:
262
285
 
263
286
  - `event` - `string`;
264
287
  - `payload` - `hash<Symbol,Any>`;
@@ -266,7 +289,7 @@ Instrumenter object should provide `notify(event, payload)` method with followin
266
289
  `redis_queued_locks` provides two instrumenters:
267
290
 
268
291
  - `RedisQueuedLocks::Instrument::ActiveSupport` - `ActiveSupport::Notifications` instrumenter
269
- that instrument events via `ActiveSupport::Notifications` api;
292
+ that instrument events via `ActiveSupport::Notifications` API;
270
293
  - `RedisQueuedLocks::Instrument::VoidNotifier` - instrumenter that does nothing;
271
294
 
272
295
  By default `RedisQueuedLocks::Client` is configured with the void notifier (which means "instrumentation is disabled").
@@ -318,11 +341,11 @@ Detalized event semantics and payload structure:
318
341
 
319
342
  ---
320
343
 
321
- ## TODO
344
+ ## Todo
322
345
 
323
346
  - `RedisQueuedLocks::Acquier::Try.try_to_lock` - detailed successful result analization;
324
347
  - `100%` test coverage;
325
- - better code stylization and interesting refactorings :)
348
+ - better code stylization and interesting refactorings;
326
349
 
327
350
  ---
328
351
 
@@ -38,7 +38,7 @@ module RedisQueuedLocks::Acquier::Release
38
38
  count: batch_size
39
39
  ) do |lock_queue|
40
40
  pipeline.call('ZREMRANGEBYSCORE', lock_queue, '-inf', '+inf')
41
- pipeline.call('EXPIRE', RedisQueuedLocks::Resource.lock_key_from_queue(lock_queue), "0")
41
+ pipeline.call('EXPIRE', RedisQueuedLocks::Resource.lock_key_from_queue(lock_queue), '0')
42
42
  end
43
43
 
44
44
  # Step B: release all locks
@@ -60,7 +60,7 @@ module RedisQueuedLocks::Acquier
60
60
  #
61
61
  # @api private
62
62
  # @since 0.1.0
63
- # rubocop:disable Metrics/MethodLength
63
+ # rubocop:disable Metrics/MethodLength, Metrics/BlockNesting
64
64
  def acquire_lock!(
65
65
  redis,
66
66
  lock_name,
@@ -147,6 +147,7 @@ module RedisQueuedLocks::Acquier
147
147
  if retry_count != nil && acq_process[:tries] >= retry_count
148
148
  # NOTE: reached the retry limit => quit from the loop
149
149
  acq_process[:should_try] = false
150
+ acq_process[:result] = :retry_limit_reached
150
151
  # NOTE: reached the retry limit => dequeue from the lock queue
151
152
  acq_dequeue.call
152
153
  # NOTE: check and raise an error
@@ -154,10 +155,11 @@ module RedisQueuedLocks::Acquier
154
155
  Failed to acquire the lock "#{lock_key}"
155
156
  for the given retry_count limit (#{retry_count} times).
156
157
  ERROR_MESSAGE
157
- elsif delay_execution(retry_delay, retry_jitter)
158
+ else
158
159
  # NOTE:
159
160
  # delay the exceution in order to prevent chaotic attempts
160
161
  # and to allow other processes and threads to obtain the lock too.
162
+ delay_execution(retry_delay, retry_jitter)
161
163
  end
162
164
  end
163
165
  end
@@ -191,12 +193,18 @@ module RedisQueuedLocks::Acquier
191
193
  { ok: true, result: acq_process[:lock_info] }
192
194
  end
193
195
  else
194
- # Step 3.b: lock is not acquired:
195
- # => drop itslef from the queue and return the reason of the failed acquirement
196
+ unless acq_process[:result] == :retry_limit_reached
197
+ # NOTE: we have only two situations if lock is not acquired:
198
+ # - time limit is reached
199
+ # - retry count limit is reached
200
+ # In other cases the lock obtaining time and tries count are infinite.
201
+ acq_process[:result] = :timeout_reached
202
+ end
203
+ # Step 3.b: lock is not acquired (acquier is dequeued by timeout callback)
196
204
  { ok: false, result: acq_process[:result] }
197
205
  end
198
206
  end
199
- # rubocop:enable Metrics/MethodLength
207
+ # rubocop:enable Metrics/MethodLength, Metrics/BlockNesting
200
208
 
201
209
  # Release the concrete lock:
202
210
  # - 1. clear lock queue: al; related processes released
@@ -208,7 +216,7 @@ module RedisQueuedLocks::Acquier
208
216
  # @param redis [RedisClient] Redis connection client.
209
217
  # @param lock_name [String] The lock name that should be released.
210
218
  # @param isntrumenter [#notify] See RedisQueuedLocks::Instrument::ActiveSupport for example.
211
- # @return [Hash<Symbol,Any>] Format: { ok: true/false, result: Any }
219
+ # @return [Hash<Symbol,Any>] Format: { ok: true/false, result: Hash<Symbil,Numeric|String> }
212
220
  #
213
221
  # @api private
214
222
  # @since 0.1.0
@@ -231,7 +239,7 @@ module RedisQueuedLocks::Acquier
231
239
  })
232
240
  end
233
241
 
234
- { ok: true, result: result }
242
+ { ok: true, result: { rel_time: rel_time, rel_key: lock_key, rel_queue: lock_key_queue } }
235
243
  end
236
244
 
237
245
  # Release all locks:
@@ -241,7 +249,7 @@ module RedisQueuedLocks::Acquier
241
249
  # @param redis [RedisClient] Redis connection client.
242
250
  # @param batch_size [Integer] The number of lock keys that should be released in a time.
243
251
  # @param isntrumenter [#notify] See RedisQueuedLocks::Instrument::ActiveSupport for example.
244
- # @return [Hash<Symbol,Any>] Format: { ok: true/false, result: Any }
252
+ # @return [Hash<Symbol,Any>] Format: { ok: true/false, result: Hash<Symbol,Numeric> }
245
253
  #
246
254
  # @api private
247
255
  # @since 0.1.0
@@ -260,7 +268,7 @@ module RedisQueuedLocks::Acquier
260
268
  })
261
269
  end
262
270
 
263
- { ok: true, result: result }
271
+ { ok: true, result: { rel_key_cnt: result[:rel_keys], rel_time: rel_time } }
264
272
  end
265
273
 
266
274
  private
@@ -5,6 +5,6 @@ module RedisQueuedLocks
5
5
  #
6
6
  # @api public
7
7
  # @since 0.0.1
8
- # @version 0.0.5
9
- VERSION = '0.0.5'
8
+ # @version 0.0.7
9
+ VERSION = '0.0.7'
10
10
  end
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
  spec.email = ['iamdaiver@gmail.com']
12
12
 
13
13
  spec.summary = 'Queued distributed locks based on Redis.'
14
- spec.description = 'Distributed lock implementation with "lock acquisition queue" ' \
14
+ spec.description = 'Distributed locks with "lock acquisition queue" ' \
15
15
  'capabilities based on the Redis Database.'
16
16
  spec.homepage = 'https://github.com/0exp/redis_queued_locks'
17
17
  spec.license = 'MIT'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis_queued_locks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rustam Ibragimov
@@ -38,8 +38,8 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.28'
41
- description: Distributed lock implementation with "lock acquisition queue" capabilities
42
- based on the Redis Database.
41
+ description: Distributed locks with "lock acquisition queue" capabilities based on
42
+ the Redis Database.
43
43
  email:
44
44
  - iamdaiver@gmail.com
45
45
  executables: []