redis_queued_locks 0.0.5 → 0.0.7

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: 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: []