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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -3
- data/README.md +262 -60
- data/lib/redis_queued_locks/acquier/acquire_lock/delay_execution.rb +2 -2
- data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock.rb +239 -12
- data/lib/redis_queued_locks/acquier/acquire_lock/with_acq_timeout.rb +2 -2
- data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire.rb +115 -0
- data/lib/redis_queued_locks/acquier/acquire_lock.rb +200 -89
- data/lib/redis_queued_locks/acquier/clear_dead_requests.rb +3 -3
- data/lib/redis_queued_locks/acquier/extend_lock_ttl.rb +3 -3
- data/lib/redis_queued_locks/acquier/is_locked.rb +2 -2
- data/lib/redis_queued_locks/acquier/is_queued.rb +2 -2
- data/lib/redis_queued_locks/acquier/keys.rb +2 -2
- data/lib/redis_queued_locks/acquier/lock_info.rb +19 -3
- data/lib/redis_queued_locks/acquier/locks.rb +13 -4
- data/lib/redis_queued_locks/acquier/queue_info.rb +2 -2
- data/lib/redis_queued_locks/acquier/queues.rb +4 -4
- data/lib/redis_queued_locks/acquier/release_all_locks.rb +4 -4
- data/lib/redis_queued_locks/acquier/release_lock.rb +4 -4
- data/lib/redis_queued_locks/acquier.rb +1 -1
- data/lib/redis_queued_locks/client.rb +50 -22
- data/lib/redis_queued_locks/debugger/interface.rb +4 -4
- data/lib/redis_queued_locks/debugger.rb +8 -8
- data/lib/redis_queued_locks/errors.rb +10 -6
- data/lib/redis_queued_locks/instrument/active_support.rb +2 -2
- data/lib/redis_queued_locks/instrument/void_notifier.rb +2 -2
- data/lib/redis_queued_locks/instrument.rb +2 -2
- data/lib/redis_queued_locks/logging/void_logger.rb +10 -10
- data/lib/redis_queued_locks/logging.rb +10 -3
- data/lib/redis_queued_locks/resource.rb +22 -16
- data/lib/redis_queued_locks/utilities.rb +2 -2
- data/lib/redis_queued_locks/version.rb +2 -2
- data/lib/redis_queued_locks.rb +2 -2
- metadata +4 -4
- 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
|
4
|
+
# @since 1.0.0
|
5
5
|
module RedisQueuedLocks::Resource
|
6
6
|
# @return [String]
|
7
7
|
#
|
8
8
|
# @api private
|
9
|
-
# @since
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
12
|
+
# @since 1.0.0
|
13
13
|
def run_non_critical(&block)
|
14
14
|
yield rescue nil
|
15
15
|
end
|
data/lib/redis_queued_locks.rb
CHANGED
@@ -7,7 +7,7 @@ require 'securerandom'
|
|
7
7
|
require 'logger'
|
8
8
|
|
9
9
|
# @api public
|
10
|
-
# @since
|
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
|
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.
|
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-
|
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/
|
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.
|
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
|