redis_queued_locks 0.0.20 → 0.0.22

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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/README.md +14 -1
  4. data/lib/redis_queued_locks/acquier/{delay.rb → acquire_lock/delay_execution.rb} +2 -2
  5. data/lib/redis_queued_locks/acquier/{try.rb → acquire_lock/try_to_lock.rb} +1 -1
  6. data/lib/redis_queued_locks/acquier/acquire_lock/with_acq_timeout.rb +29 -0
  7. data/lib/redis_queued_locks/acquier/{yield_expire.rb → acquire_lock/yield_with_expire.rb} +9 -2
  8. data/lib/redis_queued_locks/acquier/acquire_lock.rb +291 -0
  9. data/lib/redis_queued_locks/acquier/extend_lock_ttl.rb +19 -0
  10. data/lib/redis_queued_locks/acquier/is_locked.rb +18 -0
  11. data/lib/redis_queued_locks/acquier/is_queued.rb +18 -0
  12. data/lib/redis_queued_locks/acquier/keys.rb +26 -0
  13. data/lib/redis_queued_locks/acquier/lock_info.rb +57 -0
  14. data/lib/redis_queued_locks/acquier/locks.rb +26 -0
  15. data/lib/redis_queued_locks/acquier/queue_info.rb +50 -0
  16. data/lib/redis_queued_locks/acquier/queues.rb +26 -0
  17. data/lib/redis_queued_locks/acquier/release_all_locks.rb +88 -0
  18. data/lib/redis_queued_locks/acquier/release_lock.rb +76 -0
  19. data/lib/redis_queued_locks/acquier.rb +11 -557
  20. data/lib/redis_queued_locks/client.rb +34 -19
  21. data/lib/redis_queued_locks/instrument/active_support.rb +1 -1
  22. data/lib/redis_queued_locks/instrument/void_notifier.rb +1 -1
  23. data/lib/redis_queued_locks/instrument.rb +3 -3
  24. data/lib/redis_queued_locks/logging/void_logger.rb +43 -0
  25. data/lib/redis_queued_locks/logging.rb +57 -0
  26. data/lib/redis_queued_locks/utilities.rb +16 -0
  27. data/lib/redis_queued_locks/version.rb +2 -2
  28. data/lib/redis_queued_locks.rb +3 -0
  29. metadata +20 -6
  30. data/lib/redis_queued_locks/acquier/release.rb +0 -60
@@ -9,18 +9,16 @@ class RedisQueuedLocks::Client
9
9
 
10
10
  configuration do
11
11
  setting :retry_count, 3
12
- setting :retry_delay, 200 # NOTE: milliseconds
13
- setting :retry_jitter, 25 # NOTE: milliseconds
14
- setting :try_to_lock_timeout, 10 # NOTE: seconds
15
- setting :default_lock_ttl, 5_000 # NOTE: milliseconds
16
- setting :default_queue_ttl, 15 # NOTE: seconds
12
+ setting :retry_delay, 200 # NOTE: in milliseconds
13
+ setting :retry_jitter, 25 # NOTE: in milliseconds
14
+ setting :try_to_lock_timeout, 10 # NOTE: in seconds
15
+ setting :default_lock_ttl, 5_000 # NOTE: in milliseconds
16
+ setting :default_queue_ttl, 15 # NOTE: in seconds
17
17
  setting :lock_release_batch_size, 100
18
18
  setting :key_extraction_batch_size, 500
19
19
  setting :instrumenter, RedisQueuedLocks::Instrument::VoidNotifier
20
20
  setting :uniq_identifier, -> { RedisQueuedLocks::Resource.calc_uniq_identity }
21
-
22
- # TODO: setting :logger, Logger.new(IO::NULL)
23
- # TODO: setting :debug, true/false
21
+ setting :logger, RedisQueuedLocks::Logging::VoidLogger
24
22
 
25
23
  validate('retry_count') { |val| val == nil || (val.is_a?(::Integer) && val >= 0) }
26
24
  validate('retry_delay') { |val| val.is_a?(::Integer) && val >= 0 }
@@ -30,6 +28,7 @@ class RedisQueuedLocks::Client
30
28
  validate('default_queue_ttl', :integer)
31
29
  validate('lock_release_batch_size', :integer)
32
30
  validate('instrumenter') { |val| RedisQueuedLocks::Instrument.valid_interface?(val) }
31
+ validate('logger') { |val| RedisQueuedLocks::Logging.valid_interface?(val) }
33
32
  validate('uniq_identifier', :proc)
34
33
  end
35
34
 
@@ -117,7 +116,7 @@ class RedisQueuedLocks::Client
117
116
  metadata: nil,
118
117
  &block
119
118
  )
120
- RedisQueuedLocks::Acquier.acquire_lock!(
119
+ RedisQueuedLocks::Acquier::AcquireLock.acquire_lock(
121
120
  redis_client,
122
121
  lock_name,
123
122
  process_id: RedisQueuedLocks::Resource.get_process_id,
@@ -136,6 +135,7 @@ class RedisQueuedLocks::Client
136
135
  identity:,
137
136
  fail_fast:,
138
137
  metadata:,
138
+ logger: config[:logger],
139
139
  &block
140
140
  )
141
141
  end
@@ -183,7 +183,12 @@ class RedisQueuedLocks::Client
183
183
  # @api public
184
184
  # @since 0.1.0
185
185
  def unlock(lock_name)
186
- RedisQueuedLocks::Acquier.release_lock!(redis_client, lock_name, config[:instrumenter])
186
+ RedisQueuedLocks::Acquier::ReleaseLock.release_lock(
187
+ redis_client,
188
+ lock_name,
189
+ config[:instrumenter],
190
+ config[:logger]
191
+ )
187
192
  end
188
193
 
189
194
  # @param lock_name [String]
@@ -192,7 +197,7 @@ class RedisQueuedLocks::Client
192
197
  # @api public
193
198
  # @since 0.1.0
194
199
  def locked?(lock_name)
195
- RedisQueuedLocks::Acquier.locked?(redis_client, lock_name)
200
+ RedisQueuedLocks::Acquier::IsLocked.locked?(redis_client, lock_name)
196
201
  end
197
202
 
198
203
  # @param lock_name [String]
@@ -201,7 +206,7 @@ class RedisQueuedLocks::Client
201
206
  # @api public
202
207
  # @since 0.1.0
203
208
  def queued?(lock_name)
204
- RedisQueuedLocks::Acquier.queued?(redis_client, lock_name)
209
+ RedisQueuedLocks::Acquier::IsQueued.queued?(redis_client, lock_name)
205
210
  end
206
211
 
207
212
  # @param lock_name [String]
@@ -210,7 +215,7 @@ class RedisQueuedLocks::Client
210
215
  # @api public
211
216
  # @since 0.1.0
212
217
  def lock_info(lock_name)
213
- RedisQueuedLocks::Acquier.lock_info(redis_client, lock_name)
218
+ RedisQueuedLocks::Acquier::LockInfo.lock_info(redis_client, lock_name)
214
219
  end
215
220
 
216
221
  # @param lock_name [String]
@@ -219,7 +224,7 @@ class RedisQueuedLocks::Client
219
224
  # @api public
220
225
  # @since 0.1.0
221
226
  def queue_info(lock_name)
222
- RedisQueuedLocks::Acquier.queue_info(redis_client, lock_name)
227
+ RedisQueuedLocks::Acquier::QueueInfo.queue_info(redis_client, lock_name)
223
228
  end
224
229
 
225
230
  # @param lock_name [String]
@@ -229,7 +234,12 @@ class RedisQueuedLocks::Client
229
234
  # @api public
230
235
  # @since 0.1.0
231
236
  def extend_lock_ttl(lock_name, milliseconds)
232
- RedisQueuedLocks::Acquier.extend_lock_ttl(redis_client, lock_name)
237
+ RedisQueuedLocks::Acquier::ExtendLockTTL.extend_lock_ttl(
238
+ redis_client,
239
+ lock_name,
240
+ milliseconds,
241
+ config[:logger]
242
+ )
233
243
  end
234
244
 
235
245
  # @option batch_size [Integer]
@@ -239,7 +249,12 @@ class RedisQueuedLocks::Client
239
249
  # @api public
240
250
  # @since 0.1.0
241
251
  def clear_locks(batch_size: config[:lock_release_batch_size])
242
- RedisQueuedLocks::Acquier.release_all_locks!(redis_client, batch_size, config[:instrumenter])
252
+ RedisQueuedLocks::Acquier::ReleaseAllLocks.release_all_locks(
253
+ redis_client,
254
+ batch_size,
255
+ config[:instrumenter],
256
+ config[:logger]
257
+ )
243
258
  end
244
259
 
245
260
  # @option scan_size [Integer]
@@ -248,7 +263,7 @@ class RedisQueuedLocks::Client
248
263
  # @api public
249
264
  # @since 0.1.0
250
265
  def locks(scan_size: config[:key_extraction_batch_size])
251
- RedisQueuedLocks::Acquier.locks(redis_client, scan_size:)
266
+ RedisQueuedLocks::Acquier::Locks.locks(redis_client, scan_size:)
252
267
  end
253
268
 
254
269
  # @option scan_size [Integer]
@@ -257,7 +272,7 @@ class RedisQueuedLocks::Client
257
272
  # @api public
258
273
  # @since 0.1.0
259
274
  def queues(scan_size: config[:key_extraction_batch_size])
260
- RedisQueuedLocks::Acquier.queues(redis_client, scan_size:)
275
+ RedisQueuedLocks::Acquier::Queues.queues(redis_client, scan_size:)
261
276
  end
262
277
 
263
278
  # @option scan_size [Integer]
@@ -266,7 +281,7 @@ class RedisQueuedLocks::Client
266
281
  # @api public
267
282
  # @since 0.1.0
268
283
  def keys(scan_size: config[:key_extraction_batch_size])
269
- RedisQueuedLocks::Acquier.keys(redis_client, scan_size:)
284
+ RedisQueuedLocks::Acquier::Keys.keys(redis_client, scan_size:)
270
285
  end
271
286
  end
272
287
  # rubocop:enable Metrics/ClassLength
@@ -8,7 +8,7 @@ module RedisQueuedLocks::Instrument::ActiveSupport
8
8
  # @param payload [Hash<String|Symbol,Any>]
9
9
  # @return [void]
10
10
  #
11
- # @api private
11
+ # @api public
12
12
  # @since 0.1.0
13
13
  def notify(event, payload = {})
14
14
  ::ActiveSupport::Notifications.instrument(event, payload)
@@ -8,7 +8,7 @@ module RedisQueuedLocks::Instrument::VoidNotifier
8
8
  # @param payload [Hash<String|Symbol,Any>]
9
9
  # @return [void]
10
10
  #
11
- # @api private
11
+ # @api public
12
12
  # @since 0.1.0
13
13
  def notify(event, payload = {}); end
14
14
  end
@@ -25,10 +25,10 @@ module RedisQueuedLocks::Instrument
25
25
  m_obj = instrumenter.method(:notify)
26
26
  m_sig = m_obj.parameters
27
27
 
28
- f_prm = m_sig[0][0]
29
- s_prm = m_sig[1][0]
30
-
31
28
  if m_sig.size == 2
29
+ f_prm = m_sig[0][0]
30
+ s_prm = m_sig[1][0]
31
+
32
32
  # rubocop:disable Layout/MultilineOperationIndentation
33
33
  # NOTE: check the signature vairants
34
34
  f_prm == :req && s_prm == :req ||
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ module RedisQueuedLocks::Logging::VoidLogger
6
+ class << self
7
+ # @api public
8
+ # @since 0.1.0
9
+ def warn(progname = nil, &block); end
10
+
11
+ # @api public
12
+ # @since 0.1.0
13
+ def unknown(progname = nil, &block); end
14
+
15
+ # @api public
16
+ # @since 0.1.0
17
+ def log(progname = nil, &block); end
18
+
19
+ # @api public
20
+ # @since 0.1.0
21
+ def info(progname = nil, &block); end
22
+
23
+ # @api public
24
+ # @since 0.1.0
25
+ def error(progname = nil, &block); end
26
+
27
+ # @api public
28
+ # @since 0.1.0
29
+ def fatal(progname = nil, &block); end
30
+
31
+ # @api public
32
+ # @since 0.1.0
33
+ def debug(progname = nil, &block); end
34
+
35
+ # @api public
36
+ # @since 0.1.0
37
+ def add(*, &block); end
38
+
39
+ # @api public
40
+ # @since 0.1.0
41
+ def <<(message); end
42
+ end
43
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ module RedisQueuedLocks::Logging
6
+ require_relative 'logging/void_logger'
7
+
8
+ class << self
9
+ # @param logger [#debug]
10
+ # @return [Boolean]
11
+ #
12
+ # @api public
13
+ # @since 0.1.0
14
+ def valid_interface?(logger)
15
+ return true if logger.is_a?(::Logger)
16
+
17
+ # NOTE: should provide `#debug` method.
18
+ return false unless logger.respond_to?(:debug)
19
+
20
+ # NOTE:
21
+ # `#debug` method should have appropriated signature `(progname, &block)`
22
+ # Required method signature (progname, &block):
23
+ # => [[:opt, :progname], [:block, :block]]
24
+ # => [[:req, :progname], [:block, :block]]
25
+ # => [[:opt, :progname]]
26
+ # => [[:req, :progname]]
27
+ # => [[:rest], [:block, :block]]
28
+ # => [[:rest]]
29
+
30
+ m_obj = logger.method(:debug)
31
+ m_sig = m_obj.parameters
32
+
33
+ if m_sig.size == 2
34
+ # => [[:opt, :progname], [:block, :block]]
35
+ # => [[:req, :progname], [:block, :block]]
36
+ # => [[:rest], [:block, :block]]
37
+ f_prm = m_sig[0][0]
38
+ s_prm = m_sig[1][0]
39
+
40
+ # rubocop:disable Layout/MultilineOperationIndentation
41
+ f_prm == :opt && s_prm == :block ||
42
+ f_prm == :req && s_prm == :block ||
43
+ f_prm == :rest && s_prm == :block
44
+ # rubocop:enable Layout/MultilineOperationIndentation
45
+ elsif m_sig.size == 1
46
+ # => [[:opt, :progname]]
47
+ # => [[:req, :progname]]
48
+ # => [[:rest]]
49
+ prm = m_sig[0][0]
50
+
51
+ prm == :opt || prm == :req || prm == :rest
52
+ else
53
+ false
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ module RedisQueuedLocks::Utilities
6
+ module_function
7
+
8
+ # @param block [Block]
9
+ # @return [Any]
10
+ #
11
+ # @api private
12
+ # @since 0.1.0
13
+ def run_non_critical(&block)
14
+ yield rescue nil
15
+ end
16
+ end
@@ -5,6 +5,6 @@ module RedisQueuedLocks
5
5
  #
6
6
  # @api public
7
7
  # @since 0.0.1
8
- # @version 0.0.20
9
- VERSION = '0.0.20'
8
+ # @version 0.0.22
9
+ VERSION = '0.0.22'
10
10
  end
@@ -4,12 +4,15 @@ require 'redis-client'
4
4
  require 'qonfig'
5
5
  require 'timeout'
6
6
  require 'securerandom'
7
+ require 'logger'
7
8
 
8
9
  # @api public
9
10
  # @since 0.1.0
10
11
  module RedisQueuedLocks
11
12
  require_relative 'redis_queued_locks/version'
12
13
  require_relative 'redis_queued_locks/errors'
14
+ require_relative 'redis_queued_locks/utilities'
15
+ require_relative 'redis_queued_locks/logging'
13
16
  require_relative 'redis_queued_locks/data'
14
17
  require_relative 'redis_queued_locks/debugger'
15
18
  require_relative 'redis_queued_locks/resource'
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.20
4
+ version: 0.0.22
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-14 00:00:00.000000000 Z
11
+ date: 2024-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis-client
@@ -56,10 +56,21 @@ files:
56
56
  - Rakefile
57
57
  - lib/redis_queued_locks.rb
58
58
  - lib/redis_queued_locks/acquier.rb
59
- - lib/redis_queued_locks/acquier/delay.rb
60
- - lib/redis_queued_locks/acquier/release.rb
61
- - lib/redis_queued_locks/acquier/try.rb
62
- - lib/redis_queued_locks/acquier/yield_expire.rb
59
+ - lib/redis_queued_locks/acquier/acquire_lock.rb
60
+ - lib/redis_queued_locks/acquier/acquire_lock/delay_execution.rb
61
+ - lib/redis_queued_locks/acquier/acquire_lock/try_to_lock.rb
62
+ - lib/redis_queued_locks/acquier/acquire_lock/with_acq_timeout.rb
63
+ - lib/redis_queued_locks/acquier/acquire_lock/yield_with_expire.rb
64
+ - lib/redis_queued_locks/acquier/extend_lock_ttl.rb
65
+ - lib/redis_queued_locks/acquier/is_locked.rb
66
+ - lib/redis_queued_locks/acquier/is_queued.rb
67
+ - lib/redis_queued_locks/acquier/keys.rb
68
+ - lib/redis_queued_locks/acquier/lock_info.rb
69
+ - lib/redis_queued_locks/acquier/locks.rb
70
+ - lib/redis_queued_locks/acquier/queue_info.rb
71
+ - lib/redis_queued_locks/acquier/queues.rb
72
+ - lib/redis_queued_locks/acquier/release_all_locks.rb
73
+ - lib/redis_queued_locks/acquier/release_lock.rb
63
74
  - lib/redis_queued_locks/client.rb
64
75
  - lib/redis_queued_locks/data.rb
65
76
  - lib/redis_queued_locks/debugger.rb
@@ -68,7 +79,10 @@ files:
68
79
  - lib/redis_queued_locks/instrument.rb
69
80
  - lib/redis_queued_locks/instrument/active_support.rb
70
81
  - lib/redis_queued_locks/instrument/void_notifier.rb
82
+ - lib/redis_queued_locks/logging.rb
83
+ - lib/redis_queued_locks/logging/void_logger.rb
71
84
  - lib/redis_queued_locks/resource.rb
85
+ - lib/redis_queued_locks/utilities.rb
72
86
  - lib/redis_queued_locks/version.rb
73
87
  - redis_queued_locks.gemspec
74
88
  homepage: https://github.com/0exp/redis_queued_locks
@@ -1,60 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # @api private
4
- # @since 0.1.0
5
- module RedisQueuedLocks::Acquier::Release
6
- # Realease the lock: clear the lock queue and expire the lock.
7
- #
8
- # @param redis [RedisClient]
9
- # @param lock_key [String]
10
- # @param lock_key_queue [String]
11
- # @return [RedisQueuedLocks::Data,Hash<Symbol,Any>] Format: { ok: true/false, result: Any }
12
- #
13
- # @api private
14
- # @since 0.1.0
15
- def fully_release_lock(redis, lock_key, lock_key_queue)
16
- result = redis.multi do |transact|
17
- transact.call('ZREMRANGEBYSCORE', lock_key_queue, '-inf', '+inf')
18
- transact.call('EXPIRE', lock_key, '0')
19
- end
20
-
21
- RedisQueuedLocks::Data[ok: true, result:]
22
- end
23
-
24
- # Release all locks: clear all lock queus and expire all locks.
25
- #
26
- # @param redis [RedisClient]
27
- # @param batch_size [Integer]
28
- # @return [RedisQueuedLocks::Data,Hash<Symbol,Any>] Format: { ok: true/false, result: Any }
29
- #
30
- # @api private
31
- # @since 0.1.0
32
- def fully_release_all_locks(redis, batch_size)
33
- result = redis.pipelined do |pipeline|
34
- # Step A: release all queus and their related locks
35
- redis.scan(
36
- 'MATCH',
37
- RedisQueuedLocks::Resource::LOCK_QUEUE_PATTERN,
38
- count: batch_size
39
- ) do |lock_queue|
40
- # TODO: reduce unnecessary iterations
41
- pipeline.call('ZREMRANGEBYSCORE', lock_queue, '-inf', '+inf')
42
- pipeline.call('EXPIRE', RedisQueuedLocks::Resource.lock_key_from_queue(lock_queue), '0')
43
- end
44
-
45
- # Step B: release all locks
46
- redis.scan(
47
- 'MATCH',
48
- RedisQueuedLocks::Resource::LOCK_PATTERN,
49
- count: batch_size
50
- ) do |lock_key|
51
- # TODO: reduce unnecessary iterations
52
- pipeline.call('EXPIRE', lock_key, '0')
53
- end
54
- end
55
-
56
- rel_keys = result.count { |red_res| red_res == 0 }
57
-
58
- RedisQueuedLocks::Data[ok: true, result: { rel_keys: rel_keys }]
59
- end
60
- end