redis_queued_locks 1.1.0 → 1.3.0

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