redis_queued_locks 1.1.0 → 1.3.0

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -3
  3. data/README.md +262 -60
  4. data/lib/redis_queued_locks/acquier/acquire_lock/delay_execution.rb +2 -2
  5. data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock.rb +239 -12
  6. data/lib/redis_queued_locks/acquier/acquire_lock/with_acq_timeout.rb +2 -2
  7. data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire.rb +115 -0
  8. data/lib/redis_queued_locks/acquier/acquire_lock.rb +200 -89
  9. data/lib/redis_queued_locks/acquier/clear_dead_requests.rb +3 -3
  10. data/lib/redis_queued_locks/acquier/extend_lock_ttl.rb +3 -3
  11. data/lib/redis_queued_locks/acquier/is_locked.rb +2 -2
  12. data/lib/redis_queued_locks/acquier/is_queued.rb +2 -2
  13. data/lib/redis_queued_locks/acquier/keys.rb +2 -2
  14. data/lib/redis_queued_locks/acquier/lock_info.rb +19 -3
  15. data/lib/redis_queued_locks/acquier/locks.rb +13 -4
  16. data/lib/redis_queued_locks/acquier/queue_info.rb +2 -2
  17. data/lib/redis_queued_locks/acquier/queues.rb +4 -4
  18. data/lib/redis_queued_locks/acquier/release_all_locks.rb +4 -4
  19. data/lib/redis_queued_locks/acquier/release_lock.rb +4 -4
  20. data/lib/redis_queued_locks/acquier.rb +1 -1
  21. data/lib/redis_queued_locks/client.rb +50 -22
  22. data/lib/redis_queued_locks/debugger/interface.rb +4 -4
  23. data/lib/redis_queued_locks/debugger.rb +8 -8
  24. data/lib/redis_queued_locks/errors.rb +10 -6
  25. data/lib/redis_queued_locks/instrument/active_support.rb +2 -2
  26. data/lib/redis_queued_locks/instrument/void_notifier.rb +2 -2
  27. data/lib/redis_queued_locks/instrument.rb +2 -2
  28. data/lib/redis_queued_locks/logging/void_logger.rb +10 -10
  29. data/lib/redis_queued_locks/logging.rb +10 -3
  30. data/lib/redis_queued_locks/resource.rb +22 -16
  31. data/lib/redis_queued_locks/utilities.rb +2 -2
  32. data/lib/redis_queued_locks/version.rb +2 -2
  33. data/lib/redis_queued_locks.rb +2 -2
  34. metadata +4 -4
  35. data/lib/redis_queued_locks/acquier/acquire_lock/yield_with_expire.rb +0 -72
@@ -1,26 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # @api private
4
- # @since 0.1.0
4
+ # @since 1.0.0
5
5
  module RedisQueuedLocks::Resource
6
6
  # @return [String]
7
7
  #
8
8
  # @api private
9
- # @since 0.1.0
9
+ # @since 1.0.0
10
10
  KEY_PATTERN = 'rql:lock*'
11
11
 
12
12
  # @return [String]
13
13
  #
14
14
  # @api private
15
- # @since 0.1.0
15
+ # @since 1.0.0
16
16
  LOCK_PATTERN = 'rql:lock:*'
17
17
 
18
18
  # @return [String]
19
19
  #
20
20
  # @api private
21
- # @since 0.1.0
21
+ # @since 1.0.0
22
22
  LOCK_QUEUE_PATTERN = 'rql:lock_queue:*'
23
23
 
24
+ # @return [Integer] Redis time error (in milliseconds).
25
+ #
26
+ # @api private
27
+ # @since 1.3.0
28
+ REDIS_TIMESHIFT_ERROR = 2
29
+
24
30
  class << self
25
31
  # Returns 16-byte unique identifier. It is used for uniquely
26
32
  # identify current process between different nodes/pods of your application
@@ -29,7 +35,7 @@ module RedisQueuedLocks::Resource
29
35
  # @return [String]
30
36
  #
31
37
  # @api private
32
- # @since 0.1.0
38
+ # @since 1.0.0
33
39
  def calc_uniq_identity
34
40
  SecureRandom.hex(8)
35
41
  end
@@ -42,7 +48,7 @@ module RedisQueuedLocks::Resource
42
48
  # @return [String]
43
49
  #
44
50
  # @api private
45
- # @since 0.1.0
51
+ # @since 1.0.0
46
52
  def acquier_identifier(process_id, thread_id, fiber_id, ractor_id, identity)
47
53
  "rql:acq:#{process_id}/#{thread_id}/#{fiber_id}/#{ractor_id}/#{identity}"
48
54
  end
@@ -51,7 +57,7 @@ module RedisQueuedLocks::Resource
51
57
  # @return [String]
52
58
  #
53
59
  # @api private
54
- # @since 0.1.0
60
+ # @since 1.0.0
55
61
  def prepare_lock_key(lock_name)
56
62
  "rql:lock:#{lock_name}"
57
63
  end
@@ -60,7 +66,7 @@ module RedisQueuedLocks::Resource
60
66
  # @return [String]
61
67
  #
62
68
  # @api private
63
- # @since 0.1.0
69
+ # @since 1.0.0
64
70
  def prepare_lock_queue(lock_name)
65
71
  "rql:lock_queue:#{lock_name}"
66
72
  end
@@ -68,7 +74,7 @@ module RedisQueuedLocks::Resource
68
74
  # @return [Float] Redis's <Set> score that is calculated from the time (epoch) as a float.
69
75
  #
70
76
  # @api private
71
- # @since 0.1.0
77
+ # @since 1.0.0
72
78
  def calc_initial_acquier_position
73
79
  Time.now.to_f
74
80
  end
@@ -77,7 +83,7 @@ module RedisQueuedLocks::Resource
77
83
  # @return [Float] Redis's <Set> score barrier for acquiers that should be removed from queue.
78
84
  #
79
85
  # @api private
80
- # @since 0.1.0
86
+ # @since 1.0.0
81
87
  def acquier_dead_score(queue_ttl)
82
88
  Time.now.to_f - queue_ttl
83
89
  end
@@ -91,7 +97,7 @@ module RedisQueuedLocks::Resource
91
97
  # Is the lock request time limit has reached or not.
92
98
  #
93
99
  # @api private
94
- # @since 0.1.0
100
+ # @since 1.0.0
95
101
  def dead_score_reached?(acquier_position, queue_ttl)
96
102
  (acquier_position + queue_ttl) < Time.now.to_f
97
103
  end
@@ -100,7 +106,7 @@ module RedisQueuedLocks::Resource
100
106
  # @return [String]
101
107
  #
102
108
  # @api private
103
- # @since 0.1.0
109
+ # @since 1.0.0
104
110
  def lock_key_from_queue(lock_queue)
105
111
  # NOTE: 15 is a start position of the lock name
106
112
  "rql:lock:#{lock_queue[15..]}"
@@ -109,7 +115,7 @@ module RedisQueuedLocks::Resource
109
115
  # @return [Integer]
110
116
  #
111
117
  # @api private
112
- # @since 0.1.0
118
+ # @since 1.0.0
113
119
  def get_thread_id
114
120
  ::Thread.current.object_id
115
121
  end
@@ -117,7 +123,7 @@ module RedisQueuedLocks::Resource
117
123
  # @return [Integer]
118
124
  #
119
125
  # @api private
120
- # @since 0.1.0
126
+ # @since 1.0.0
121
127
  def get_fiber_id
122
128
  ::Fiber.current.object_id
123
129
  end
@@ -125,7 +131,7 @@ module RedisQueuedLocks::Resource
125
131
  # @return [Integer]
126
132
  #
127
133
  # @api private
128
- # @since 0.1.0
134
+ # @since 1.0.0
129
135
  def get_ractor_id
130
136
  ::Ractor.current.object_id
131
137
  end
@@ -133,7 +139,7 @@ module RedisQueuedLocks::Resource
133
139
  # @return [Integer]
134
140
  #
135
141
  # @api private
136
- # @since 0.1.0
142
+ # @since 1.0.0
137
143
  def get_process_id
138
144
  ::Process.pid
139
145
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # @api private
4
- # @since 0.1.0
4
+ # @since 1.0.0
5
5
  module RedisQueuedLocks::Utilities
6
6
  module_function
7
7
 
@@ -9,7 +9,7 @@ module RedisQueuedLocks::Utilities
9
9
  # @return [Any]
10
10
  #
11
11
  # @api private
12
- # @since 0.1.0
12
+ # @since 1.0.0
13
13
  def run_non_critical(&block)
14
14
  yield rescue nil
15
15
  end
@@ -5,6 +5,6 @@ module RedisQueuedLocks
5
5
  #
6
6
  # @api public
7
7
  # @since 0.0.1
8
- # @version 1.1.0
9
- VERSION = '1.1.0'
8
+ # @version 1.3.0
9
+ VERSION = '1.3.0'
10
10
  end
@@ -7,7 +7,7 @@ require 'securerandom'
7
7
  require 'logger'
8
8
 
9
9
  # @api public
10
- # @since 0.1.0
10
+ # @since 1.0.0
11
11
  module RedisQueuedLocks
12
12
  require_relative 'redis_queued_locks/version'
13
13
  require_relative 'redis_queued_locks/errors'
@@ -20,6 +20,6 @@ module RedisQueuedLocks
20
20
  require_relative 'redis_queued_locks/instrument'
21
21
  require_relative 'redis_queued_locks/client'
22
22
 
23
- # @since 0.1.0
23
+ # @since 1.0.0
24
24
  extend RedisQueuedLocks::Debugger::Interface
25
25
  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: 1.1.0
4
+ version: 1.3.0
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-04-02 00:00:00.000000000 Z
11
+ date: 2024-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis-client
@@ -60,7 +60,7 @@ files:
60
60
  - lib/redis_queued_locks/acquier/acquire_lock/delay_execution.rb
61
61
  - lib/redis_queued_locks/acquier/acquire_lock/try_to_lock.rb
62
62
  - lib/redis_queued_locks/acquier/acquire_lock/with_acq_timeout.rb
63
- - lib/redis_queued_locks/acquier/acquire_lock/yield_with_expire.rb
63
+ - lib/redis_queued_locks/acquier/acquire_lock/yield_expire.rb
64
64
  - lib/redis_queued_locks/acquier/clear_dead_requests.rb
65
65
  - lib/redis_queued_locks/acquier/extend_lock_ttl.rb
66
66
  - lib/redis_queued_locks/acquier/is_locked.rb
@@ -108,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
108
  - !ruby/object:Gem::Version
109
109
  version: '0'
110
110
  requirements: []
111
- rubygems_version: 3.5.1
111
+ rubygems_version: 3.3.7
112
112
  signing_key:
113
113
  specification_version: 4
114
114
  summary: Queued distributed locks based on Redis.
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # @api private
4
- # @since 0.1.0
5
- module RedisQueuedLocks::Acquier::AcquireLock::YieldWithExpire
6
- # @since 0.1.0
7
- extend RedisQueuedLocks::Utilities
8
-
9
- # @param redis [RedisClient] Redis connection manager.
10
- # @param logger [::Logger,#debug] Logger object.
11
- # @param lock_key [String] Lock key to be expired.
12
- # @param acquier_id [String] Acquier identifier.
13
- # @param timed [Boolean] Should the lock be wrapped by Tiemlout with with lock's ttl
14
- # @param ttl_shift [Float] Lock's TTL shifting. Should affect block's ttl. In millisecodns.
15
- # @param ttl [Integer,NilClass] Lock's time to live (in ms). Nil means "without timeout".
16
- # @param queue_ttl [Integer] Lock request lifetime.
17
- # @param block [Block] Custom logic that should be invoked unter the obtained lock.
18
- # @return [Any,NilClass] nil is returned no block parametr is provided.
19
- #
20
- # @api private
21
- # @since 0.1.0
22
- def yield_with_expire(
23
- redis,
24
- logger,
25
- lock_key,
26
- acquier_id,
27
- timed,
28
- ttl_shift,
29
- ttl,
30
- queue_ttl,
31
- &block
32
- )
33
- if block_given?
34
- if timed && ttl != nil
35
- timeout = ((ttl - ttl_shift) / 1000.0).yield_self { |time| (time < 0) ? 0.0 : time }
36
- yield_with_timeout(timeout, lock_key, ttl, &block)
37
- else
38
- yield
39
- end
40
- end
41
- ensure
42
- run_non_critical do
43
- logger.debug do
44
- "[redis_queued_locks.expire_lock] " \
45
- "lock_key => '#{lock_key}' " \
46
- "queue_ttl => #{queue_ttl} " \
47
- "acq_id => '#{acquier_id}'"
48
- end
49
- end
50
- redis.call('EXPIRE', lock_key, '0')
51
- end
52
-
53
- private
54
-
55
- # @param timeout [Float]
56
- # @parma lock_key [String]
57
- # @param lock_ttl [Integer,NilClass]
58
- # @param block [Blcok]
59
- # @return [Any]
60
- #
61
- # @api private
62
- # @since 0.1.0
63
- def yield_with_timeout(timeout, lock_key, lock_ttl, &block)
64
- ::Timeout.timeout(timeout, &block)
65
- rescue ::Timeout::Error
66
- raise(
67
- RedisQueuedLocks::TimedLockTimeoutError,
68
- "Passed <timed> block of code exceeded " \
69
- "the lock TTL (lock: \"#{lock_key}\", ttl: #{lock_ttl})"
70
- )
71
- end
72
- end