redis_queued_locks 0.0.20 → 0.0.22

Sign up to get free protection for your applications and to get access to all the features.
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