redis_queued_locks 1.21.0 → 1.23.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/.claude/project-overview.md +294 -51
- data/.claude/rules/acquirer.md +16 -11
- data/.claude/rules/arguments.md +2 -2
- data/.claude/rules/changelog.md +27 -0
- data/.claude/rules/git.md +1 -1
- data/.claude/rules/logic.md +14 -15
- data/.claude/rules/swarm.md +3 -4
- data/.claude/rules/tests.md +9 -9
- data/.claude/rules/type-checking.md +14 -16
- data/.claude/rules/visitors.md +11 -9
- data/.claude/skills/rql-code-review/SKILL.md +129 -47
- data/.ruby-version +1 -1
- data/CHANGELOG.md +122 -245
- data/CLAUDE.md +12 -10
- data/README.md +516 -175
- data/Rakefile +11 -0
- data/lib/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue.rb +4 -4
- data/lib/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rb +28 -12
- data/lib/redis_queued_locks/acquirer/acquire_lock/log_visitor.rb +38 -16
- data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rb +92 -15
- data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rb +945 -272
- data/lib/redis_queued_locks/acquirer/acquire_lock.rb +82 -32
- data/lib/redis_queued_locks/acquirer/clear_dead_requests.rb +240 -45
- data/lib/redis_queued_locks/acquirer/extend_lock_ttl.rb +15 -13
- data/lib/redis_queued_locks/acquirer/keys.rb +6 -2
- data/lib/redis_queued_locks/acquirer/lock_series/instr_visitor.rb +243 -0
- data/lib/redis_queued_locks/acquirer/lock_series/log_visitor.rb +472 -0
- data/lib/redis_queued_locks/acquirer/lock_series/release_lock_series.rb +181 -0
- data/lib/redis_queued_locks/acquirer/lock_series/try_to_lock_series.rb +1051 -0
- data/lib/redis_queued_locks/acquirer/lock_series.rb +948 -0
- data/lib/redis_queued_locks/acquirer/locks.rb +6 -2
- data/lib/redis_queued_locks/acquirer/queue_info.rb +30 -7
- data/lib/redis_queued_locks/acquirer/queues.rb +17 -6
- data/lib/redis_queued_locks/acquirer/release_all_locks.rb +6 -2
- data/lib/redis_queued_locks/acquirer/release_locks_of.rb +6 -2
- data/lib/redis_queued_locks/acquirer.rb +1 -1
- data/lib/redis_queued_locks/client.rb +116 -44
- data/lib/redis_queued_locks/config.rb +93 -1
- data/lib/redis_queued_locks/resource.rb +124 -9
- data/lib/redis_queued_locks/swarm/swarm_element/threaded.rb +6 -5
- data/lib/redis_queued_locks/swarm/zombie_info.rb +6 -2
- data/lib/redis_queued_locks/version.rb +2 -2
- data/rbs_collection.lock.yaml +4 -0
- data/rbs_collection.yaml +2 -1
- data/redis_queued_locks.gemspec +21 -14
- data/sig/manifest.yml +1 -0
- data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rbs +2 -2
- data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue.rbs +2 -2
- data/sig/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rbs +12 -6
- data/sig/redis_queued_locks/acquirer/acquire_lock/log_visitor.rbs +21 -14
- data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rbs +61 -40
- data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rbs +160 -11
- data/sig/redis_queued_locks/acquirer/acquire_lock/{yield_with_expire → yield_expire}/log_visitor.rbs +4 -4
- data/sig/redis_queued_locks/acquirer/acquire_lock/yield_expire.rbs +2 -2
- data/sig/redis_queued_locks/acquirer/acquire_lock.rbs +5 -3
- data/sig/redis_queued_locks/acquirer/clear_dead_requests.rbs +14 -1
- data/sig/redis_queued_locks/acquirer/extend_lock_ttl.rbs +2 -2
- data/sig/redis_queued_locks/acquirer/lock_series/instr_visitor.rbs +102 -0
- data/sig/redis_queued_locks/acquirer/lock_series/log_visitor.rbs +154 -0
- data/sig/redis_queued_locks/acquirer/lock_series/release_lock_series.rbs +37 -0
- data/sig/redis_queued_locks/acquirer/lock_series/try_to_lock_series.rbs +198 -0
- data/sig/redis_queued_locks/acquirer/lock_series.rbs +106 -0
- data/sig/redis_queued_locks/acquirer/queues.rbs +1 -1
- data/sig/redis_queued_locks/client.rbs +77 -7
- data/sig/redis_queued_locks/config.rbs +54 -1
- data/sig/redis_queued_locks/instrument/sampler.rbs +3 -1
- data/sig/redis_queued_locks/instrument/void_notifier.rbs +3 -1
- data/sig/redis_queued_locks/logging/sampler.rbs +3 -1
- data/sig/redis_queued_locks/resource.rbs +22 -12
- data/sig/redis_queued_locks/swarm/swarm_element/threaded.rbs +1 -1
- data/sig/redis_queued_locks/utilities.rbs +2 -1
- data/sig/redis_queued_locks.rbs +7 -0
- metadata +35 -13
- data/lib/redis_queued_locks/acquirer/lock_series_poc/instr_visitor.rb +0 -56
- data/lib/redis_queued_locks/acquirer/lock_series_poc/log_visitor.rb +0 -95
- data/lib/redis_queued_locks/acquirer/lock_series_poc.rb +0 -484
- /data/sig/redis_queued_locks/{acquier.rbs → acquirer.rbs} +0 -0
|
@@ -44,9 +44,10 @@ module RedisQueuedLocks
|
|
|
44
44
|
?retry_jitter: Integer,
|
|
45
45
|
?raise_errors: bool,
|
|
46
46
|
?fail_fast: bool,
|
|
47
|
-
?conflict_strategy:
|
|
48
|
-
?
|
|
49
|
-
?access_strategy:
|
|
47
|
+
?conflict_strategy: RQL::conflictStrategy,
|
|
48
|
+
?rw_mode: RQL::readWriteMode,
|
|
49
|
+
?access_strategy: RQL::accessStrategy,
|
|
50
|
+
?priority: RQL::lockPriority,
|
|
50
51
|
?identity: String,
|
|
51
52
|
?meta: Hash[String|Symbol,untyped]?,
|
|
52
53
|
?detailed_acq_timeout_error: bool,
|
|
@@ -75,9 +76,10 @@ module RedisQueuedLocks
|
|
|
75
76
|
?retry_delay: Integer,
|
|
76
77
|
?retry_jitter: Integer,
|
|
77
78
|
?fail_fast: bool,
|
|
78
|
-
?conflict_strategy:
|
|
79
|
-
?
|
|
80
|
-
?access_strategy:
|
|
79
|
+
?conflict_strategy: RQL::conflictStrategy,
|
|
80
|
+
?rw_mode: RQL::readWriteMode,
|
|
81
|
+
?access_strategy: RQL::accessStrategy,
|
|
82
|
+
?priority: RQL::lockPriority,
|
|
81
83
|
?identity: String,
|
|
82
84
|
?instrumenter: RQL::instrObj,
|
|
83
85
|
?meta: Hash[String|Symbol,untyped]?,
|
|
@@ -95,6 +97,73 @@ module RedisQueuedLocks
|
|
|
95
97
|
?instr_sample_this: bool,
|
|
96
98
|
) ?{ (?) -> untyped } -> RQL::Acquirer::AcquireLock::acquireResult
|
|
97
99
|
|
|
100
|
+
def lock_series: (
|
|
101
|
+
*String lock_names,
|
|
102
|
+
?detailed_result: bool,
|
|
103
|
+
?ttl: Integer,
|
|
104
|
+
?queue_ttl: Integer,
|
|
105
|
+
?lock_index_grace_period: Integer,
|
|
106
|
+
?timeout: Integer?,
|
|
107
|
+
?timed: bool,
|
|
108
|
+
?retry_count: Integer?,
|
|
109
|
+
?retry_delay: Integer,
|
|
110
|
+
?retry_jitter: Integer,
|
|
111
|
+
?raise_errors: bool,
|
|
112
|
+
?fail_fast: bool,
|
|
113
|
+
?conflict_strategy: RQL::conflictStrategy,
|
|
114
|
+
?rw_mode: RQL::readWriteMode,
|
|
115
|
+
?access_strategy: RQL::accessStrategy,
|
|
116
|
+
?priority: RQL::lockPriority,
|
|
117
|
+
?identity: String,
|
|
118
|
+
?meta: Hash[String|Symbol,untyped]?,
|
|
119
|
+
?detailed_acq_timeout_error: bool,
|
|
120
|
+
?logger: RQL::loggerObj,
|
|
121
|
+
?log_lock_try: bool,
|
|
122
|
+
?instrumenter: RQL::instrObj,
|
|
123
|
+
?instrument: untyped?,
|
|
124
|
+
?log_sampling_enabled: bool,
|
|
125
|
+
?log_sampling_percent: Integer,
|
|
126
|
+
?log_sampler: RQL::Logging::samplerObj,
|
|
127
|
+
?log_sample_this: bool,
|
|
128
|
+
?instr_sampling_enabled: bool,
|
|
129
|
+
?instr_sampling_percent: Integer,
|
|
130
|
+
?instr_sampler: RQL::Instrument::samplerObj,
|
|
131
|
+
?instr_sample_this: bool
|
|
132
|
+
) ?{ (?) -> untyped } -> RQL::Acquirer::LockSeries::lockSeriesResult
|
|
133
|
+
|
|
134
|
+
def lock_series!: (
|
|
135
|
+
*String lock_names,
|
|
136
|
+
?detailed_result: bool,
|
|
137
|
+
?ttl: Integer,
|
|
138
|
+
?queue_ttl: Integer,
|
|
139
|
+
?lock_index_grace_period: Integer,
|
|
140
|
+
?timeout: Integer?,
|
|
141
|
+
?timed: bool,
|
|
142
|
+
?retry_count: Integer?,
|
|
143
|
+
?retry_delay: Integer,
|
|
144
|
+
?retry_jitter: Integer,
|
|
145
|
+
?fail_fast: bool,
|
|
146
|
+
?conflict_strategy: RQL::conflictStrategy,
|
|
147
|
+
?rw_mode: RQL::readWriteMode,
|
|
148
|
+
?access_strategy: RQL::accessStrategy,
|
|
149
|
+
?priority: RQL::lockPriority,
|
|
150
|
+
?identity: String,
|
|
151
|
+
?meta: Hash[String|Symbol,untyped]?,
|
|
152
|
+
?detailed_acq_timeout_error: bool,
|
|
153
|
+
?logger: RQL::loggerObj,
|
|
154
|
+
?log_lock_try: bool,
|
|
155
|
+
?instrumenter: RQL::instrObj,
|
|
156
|
+
?instrument: untyped?,
|
|
157
|
+
?log_sampling_enabled: bool,
|
|
158
|
+
?log_sampling_percent: Integer,
|
|
159
|
+
?log_sampler: RQL::Logging::samplerObj,
|
|
160
|
+
?log_sample_this: bool,
|
|
161
|
+
?instr_sampling_enabled: bool,
|
|
162
|
+
?instr_sampling_percent: Integer,
|
|
163
|
+
?instr_sampler: RQL::Instrument::samplerObj,
|
|
164
|
+
?instr_sample_this: bool
|
|
165
|
+
) ?{ (?) -> untyped } -> RQL::Acquirer::LockSeries::lockSeriesResult
|
|
166
|
+
|
|
98
167
|
def unlock: (
|
|
99
168
|
String lock_name,
|
|
100
169
|
?logger: RQL::loggerObj,
|
|
@@ -158,7 +227,7 @@ module RedisQueuedLocks
|
|
|
158
227
|
def extend_lock_ttl: (
|
|
159
228
|
String lock_name,
|
|
160
229
|
Integer milliseconds,
|
|
161
|
-
?
|
|
230
|
+
?rw_mode: RQL::readWriteMode,
|
|
162
231
|
?all_read_locks: bool,
|
|
163
232
|
?identity: String,
|
|
164
233
|
?logger: RQL::loggerObj,
|
|
@@ -242,6 +311,7 @@ module RedisQueuedLocks
|
|
|
242
311
|
def clear_dead_requests: (
|
|
243
312
|
?dead_ttl: Integer,
|
|
244
313
|
?scan_size: Integer,
|
|
314
|
+
?by_priority: bool,
|
|
245
315
|
?logger: RQL::loggerObj,
|
|
246
316
|
?instrumenter: RQL::instrObj,
|
|
247
317
|
?instrument: untyped?,
|
|
@@ -7,11 +7,60 @@ module RedisQueuedLocks
|
|
|
7
7
|
type configState = Hash[String,untyped]
|
|
8
8
|
|
|
9
9
|
@config_state: configState
|
|
10
|
+
@configuring: bool
|
|
10
11
|
attr_reader config_state: configState
|
|
11
12
|
|
|
12
13
|
def initialize: () ?{ (RedisQueuedLocks::Config) -> void } -> void
|
|
13
14
|
def configure: () ?{ (RedisQueuedLocks::Config) -> void } -> void
|
|
14
|
-
|
|
15
|
+
# NOTE: (typed config lookups) one overload per config key (the `setting` list of `config.rb`):
|
|
16
|
+
# Steep checks `config['...']` defaults in `Client` and rejects unknown keys;
|
|
17
|
+
# keep this table in sync with `setting`/`validate`;
|
|
18
|
+
def []: ("retry_count") -> Integer?
|
|
19
|
+
| ("retry_delay") -> Integer
|
|
20
|
+
| ("retry_jitter") -> Integer
|
|
21
|
+
| ("try_to_lock_timeout") -> Integer?
|
|
22
|
+
| ("default_lock_ttl") -> Integer
|
|
23
|
+
| ("default_queue_ttl") -> Integer
|
|
24
|
+
| ("detailed_acq_timeout_error") -> bool
|
|
25
|
+
| ("lock_release_batch_size") -> Integer
|
|
26
|
+
| ("clear_locks_of__lock_scan_size") -> Integer
|
|
27
|
+
| ("clear_locks_of__queue_scan_size") -> Integer
|
|
28
|
+
| ("key_extraction_batch_size") -> Integer
|
|
29
|
+
| ("instrumenter") -> RedisQueuedLocks::instrObj
|
|
30
|
+
| ("uniq_identifier") -> ^() -> String
|
|
31
|
+
| ("logger") -> RedisQueuedLocks::loggerObj
|
|
32
|
+
| ("log_lock_try") -> bool
|
|
33
|
+
| ("dead_request_ttl") -> Integer
|
|
34
|
+
| ("lock_index_enabled") -> bool
|
|
35
|
+
| ("lock_index_grace_period") -> Integer
|
|
36
|
+
| ("is_timed_by_default") -> bool
|
|
37
|
+
| ("default_conflict_strategy") -> RedisQueuedLocks::conflictStrategy
|
|
38
|
+
| ("default_access_strategy") -> RedisQueuedLocks::accessStrategy
|
|
39
|
+
| ("lock_priorities") -> Hash[Symbol, Integer]
|
|
40
|
+
| ("default_lock_priority") -> RedisQueuedLocks::lockPriority
|
|
41
|
+
| ("log_sampling_enabled") -> bool
|
|
42
|
+
| ("log_sampling_percent") -> Integer
|
|
43
|
+
| ("log_sampler") -> RedisQueuedLocks::Logging::samplerObj
|
|
44
|
+
| ("instr_sampling_enabled") -> bool
|
|
45
|
+
| ("instr_sampling_percent") -> Integer
|
|
46
|
+
| ("instr_sampler") -> RedisQueuedLocks::Instrument::samplerObj
|
|
47
|
+
| ("swarm.auto_swarm") -> bool
|
|
48
|
+
| ("swarm.supervisor.liveness_probing_period") -> Integer
|
|
49
|
+
| ("swarm.probe_hosts.enabled_for_swarm") -> bool
|
|
50
|
+
| ("swarm.probe_hosts.probe_period") -> Integer
|
|
51
|
+
| ("swarm.probe_hosts.redis_config.sentinel") -> bool
|
|
52
|
+
| ("swarm.probe_hosts.redis_config.pooled") -> bool
|
|
53
|
+
| ("swarm.probe_hosts.redis_config.config") -> Hash[untyped,untyped]
|
|
54
|
+
| ("swarm.probe_hosts.redis_config.pool_config") -> Hash[untyped,untyped]
|
|
55
|
+
| ("swarm.flush_zombies.enabled_for_swarm") -> bool
|
|
56
|
+
| ("swarm.flush_zombies.zombie_ttl") -> Integer
|
|
57
|
+
| ("swarm.flush_zombies.zombie_lock_scan_size") -> Integer
|
|
58
|
+
| ("swarm.flush_zombies.zombie_queue_scan_size") -> Integer
|
|
59
|
+
| ("swarm.flush_zombies.zombie_flush_period") -> Integer
|
|
60
|
+
| ("swarm.flush_zombies.redis_config.sentinel") -> bool
|
|
61
|
+
| ("swarm.flush_zombies.redis_config.pooled") -> bool
|
|
62
|
+
| ("swarm.flush_zombies.redis_config.config") -> Hash[untyped,untyped]
|
|
63
|
+
| ("swarm.flush_zombies.redis_config.pool_config") -> Hash[untyped,untyped]
|
|
15
64
|
def []=: (String config_key, untyped config_value) -> void
|
|
16
65
|
def slice: (String config_key_pattern) -> configState
|
|
17
66
|
|
|
@@ -19,5 +68,9 @@ module RedisQueuedLocks
|
|
|
19
68
|
|
|
20
69
|
def prevent_key__non_existent: (String config_key) -> void
|
|
21
70
|
def prevent_key__invalid_type: (String config_key, untyped config_value) -> void
|
|
71
|
+
def prevent_default_priority__unknown_name: (
|
|
72
|
+
Hash[Symbol, Integer] lock_priorities,
|
|
73
|
+
RedisQueuedLocks::lockPriority default_lock_priority
|
|
74
|
+
) -> void
|
|
22
75
|
end
|
|
23
76
|
end
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
module RedisQueuedLocks
|
|
2
2
|
module Instrument
|
|
3
3
|
module Sampler
|
|
4
|
-
|
|
4
|
+
# NOTE: (rbs test) not hooked: `valid_sampler?` introspects `#parameters` of this method,
|
|
5
|
+
# and a hooked method has the `(*rest, &block)` parameters;
|
|
6
|
+
%a{rbs:test:skip} def self.sampling_happened?: (Integer sampling_percent) -> bool
|
|
5
7
|
end
|
|
6
8
|
end
|
|
7
9
|
end
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
module RedisQueuedLocks
|
|
2
2
|
module Instrument
|
|
3
3
|
module VoidNotifier
|
|
4
|
-
|
|
4
|
+
# NOTE: (rbs test) not hooked: `Instrument.valid_interface?` introspects `#parameters` of `notify`,
|
|
5
|
+
# and a hooked method has the `(*rest, &block)` parameters;
|
|
6
|
+
%a{rbs:test:skip} def self.notify: (String event, ?Hash[untyped,untyped] payload) -> void
|
|
5
7
|
end
|
|
6
8
|
end
|
|
7
9
|
end
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
module RedisQueuedLocks
|
|
2
2
|
module Logging
|
|
3
3
|
module Sampler
|
|
4
|
-
|
|
4
|
+
# NOTE: (rbs test) not hooked: `valid_sampler?` introspects `#parameters` of this method,
|
|
5
|
+
# and a hooked method has the `(*rest, &block)` parameters;
|
|
6
|
+
%a{rbs:test:skip} def self.sampling_happened?: (Integer sampling_percent) -> bool
|
|
5
7
|
end
|
|
6
8
|
end
|
|
7
9
|
end
|
|
@@ -10,6 +10,9 @@ module RedisQueuedLocks
|
|
|
10
10
|
SWARM_KEY: String
|
|
11
11
|
LOCK_INDEX_KEY: String
|
|
12
12
|
REDIS_TIMESHIFT_ERROR: Integer
|
|
13
|
+
MIN_LOCK_PRIORITY: Integer
|
|
14
|
+
MAX_LOCK_PRIORITY: Integer
|
|
15
|
+
LOCK_PRIORITY_BAND: Integer
|
|
13
16
|
|
|
14
17
|
def self.calc_uniq_identity: () -> String
|
|
15
18
|
def self.acquirer_identifier: (
|
|
@@ -27,24 +30,31 @@ module RedisQueuedLocks
|
|
|
27
30
|
String identity
|
|
28
31
|
) -> String
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def self.
|
|
34
|
-
def self.
|
|
33
|
+
# NOTE: (rbs test) `%a{rbs:test:skip}`: these functions run inside the zombie flusher Ractor
|
|
34
|
+
# (`FlushZombies.flush_zombies`); rbs/test hooks read `RBS.logger` and raise
|
|
35
|
+
# `Ractor::IsolationError` there, so they are not hooked (Steep still checks them).
|
|
36
|
+
%a{rbs:test:skip} def self.prepare_lock_key: (String lock_name) -> String
|
|
37
|
+
%a{rbs:test:skip} def self.prepare_lock_queue: (String lock_name) -> String
|
|
38
|
+
%a{rbs:test:skip} def self.prepare_read_lock_queue: (String lock_name) -> String
|
|
39
|
+
%a{rbs:test:skip} def self.prepare_lock_readers: (String lock_name) -> String
|
|
40
|
+
%a{rbs:test:skip} def self.prepare_read_lock_key: (String lock_name, String acquirer_id) -> String
|
|
35
41
|
def self.lock_queue_rw_mode: (String lock_queue) -> String?
|
|
36
42
|
type lockKeyFamily = :lock | :lock_queue | :lock_readers | :read_lock_queue | :read_lock
|
|
37
|
-
def self.lock_key_family: (String key) -> lockKeyFamily?
|
|
43
|
+
%a{rbs:test:skip} def self.lock_key_family: (String key) -> lockKeyFamily?
|
|
38
44
|
def self.lock_name_from_key: (String key, lockKeyFamily? key_family) -> String?
|
|
39
|
-
def self.lock_index_time: () -> Integer
|
|
40
|
-
def self.
|
|
45
|
+
%a{rbs:test:skip} def self.lock_index_time: () -> Integer
|
|
46
|
+
def self.lock_index_score_expired?: (String lock_index_score, Integer lock_index_time) -> bool
|
|
47
|
+
%a{rbs:test:skip} def self.lock_name_from_readers: (String lock_readers_key) -> String
|
|
41
48
|
def self.lock_key_from_readers: (String lock_readers_key) -> String
|
|
42
|
-
def self.host_identifier_from_acquirer: (String acquirer_id) -> String
|
|
49
|
+
%a{rbs:test:skip} def self.host_identifier_from_acquirer: (String acquirer_id) -> String
|
|
43
50
|
def self.redis_time_ms: (Array[String] redis_time) -> Integer
|
|
44
|
-
def self.calc_initial_acquirer_position: () -> Float
|
|
51
|
+
def self.calc_initial_acquirer_position: (Integer priority) -> Float
|
|
45
52
|
def self.acquirer_dead_score: (Integer|Float queue_ttl) -> Float
|
|
46
|
-
def self.
|
|
47
|
-
def self.
|
|
53
|
+
def self.lock_priority_band_floor: (Integer priority) -> Integer
|
|
54
|
+
def self.lock_priority_band_dead_score: (Float dead_score, Integer priority) -> Float
|
|
55
|
+
def self.lock_request_priority: (Integer|Float acquirer_position) -> Integer
|
|
56
|
+
%a{rbs:test:skip} def self.calc_zombie_score: (Float zombie_ttl) -> Float
|
|
57
|
+
def self.dead_score_reached?: (Float acquirer_position, Integer priority, Integer queue_ttl) -> bool
|
|
48
58
|
def self.lock_key_from_queue: (String lock_queue) -> String?
|
|
49
59
|
def self.get_thread_id: () -> Integer
|
|
50
60
|
def self.get_fiber_id: () -> Integer
|
|
@@ -54,7 +54,7 @@ module RedisQueuedLocks
|
|
|
54
54
|
def swarm_loop__start: () -> void
|
|
55
55
|
def swarm_loop__stop: () -> void
|
|
56
56
|
def swarm_loop__send_command: (Symbol command) -> swarmLoopReply?
|
|
57
|
-
def
|
|
57
|
+
def swarm_element__terminate: () -> void
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
end
|
|
@@ -7,7 +7,8 @@ module RedisQueuedLocks
|
|
|
7
7
|
def self?.run_non_critical: () { (?) -> untyped } -> untyped?
|
|
8
8
|
def self?.ractor_status: (Ractor ractor) -> String
|
|
9
9
|
def self?.ractor_alive?: (Ractor ractor) -> bool
|
|
10
|
-
|
|
10
|
+
# NOTE: (rbs test) runs inside the element Ractor (`Isolated.swarm_loop`), see `resource.rbs`;
|
|
11
|
+
%a{rbs:test:skip} def self?.thread_state: (Thread thread) -> String
|
|
11
12
|
def self?.clock_gettime: () -> Integer
|
|
12
13
|
def self?.ruby_over_4?: () -> bool
|
|
13
14
|
end
|
data/sig/redis_queued_locks.rbs
CHANGED
|
@@ -10,5 +10,12 @@ module RedisQueuedLocks
|
|
|
10
10
|
type loggerObj = Object & _Loggable
|
|
11
11
|
type instrObj = Object & _Instrumentable
|
|
12
12
|
|
|
13
|
+
type readWriteMode = :read | :write
|
|
14
|
+
type accessStrategy = :queued | :random
|
|
15
|
+
type conflictStrategy = :wait_for_lock | :work_through | :extendable_work_through | :dead_locking
|
|
16
|
+
# NOTE: (lock request priorities) an Integer priority or a priority name of
|
|
17
|
+
# `config['lock_priorities']` (resolved by `AcquireLock.acquire_lock`);
|
|
18
|
+
type lockPriority = Integer | Symbol
|
|
19
|
+
|
|
13
20
|
extend ::RedisQueuedLocks::Debugger::Interface
|
|
14
21
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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.23.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rustam Ibragimov
|
|
@@ -23,12 +23,26 @@ dependencies:
|
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '0.20'
|
|
26
|
-
description:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
description: |
|
|
27
|
+
RedisQueuedLocks (aka RQL, aka RQL-lock) - distributed locks with
|
|
28
|
+
"prioritized lock acquisition queue" capabilities based on the Redis Database.
|
|
29
|
+
|
|
30
|
+
Each lock request is put into the request queue
|
|
31
|
+
(each lock is hosted by its own queue separately from other queues)
|
|
32
|
+
and processed in order of their priority: requests of a higher priority go first,
|
|
33
|
+
requests of the same priority are processed in FIFO order.
|
|
34
|
+
Each lock request lives some period of time (RTTL) (with requeue capabilities)
|
|
35
|
+
which guarantees the request queue will never be stacked.
|
|
36
|
+
|
|
37
|
+
In addition to the classic queued (FIFO) strategy RQL supports random (RANDOM)
|
|
38
|
+
lock obtaining strategy when any acquirer from the lock queue
|
|
39
|
+
can obtain the lock regardless the position in the queue.
|
|
40
|
+
|
|
41
|
+
Supports lock request prioritization, Read/Write locks and Reentrant locks.
|
|
42
|
+
|
|
43
|
+
Provides flexible invocation flow, parametrized limits (lock request ttl, lock ttl,
|
|
44
|
+
queue ttl, lock attempts limit, fast failing, etc), zombie locks elimination,
|
|
45
|
+
lock indexing, logging and instrumentation (and much more).
|
|
32
46
|
email:
|
|
33
47
|
- iamdaiver@gmail.com
|
|
34
48
|
executables: []
|
|
@@ -38,6 +52,7 @@ files:
|
|
|
38
52
|
- ".claude/project-overview.md"
|
|
39
53
|
- ".claude/rules/acquirer.md"
|
|
40
54
|
- ".claude/rules/arguments.md"
|
|
55
|
+
- ".claude/rules/changelog.md"
|
|
41
56
|
- ".claude/rules/git.md"
|
|
42
57
|
- ".claude/rules/logic.md"
|
|
43
58
|
- ".claude/rules/swarm.md"
|
|
@@ -78,9 +93,11 @@ files:
|
|
|
78
93
|
- lib/redis_queued_locks/acquirer/is_queued.rb
|
|
79
94
|
- lib/redis_queued_locks/acquirer/keys.rb
|
|
80
95
|
- lib/redis_queued_locks/acquirer/lock_info.rb
|
|
81
|
-
- lib/redis_queued_locks/acquirer/
|
|
82
|
-
- lib/redis_queued_locks/acquirer/
|
|
83
|
-
- lib/redis_queued_locks/acquirer/
|
|
96
|
+
- lib/redis_queued_locks/acquirer/lock_series.rb
|
|
97
|
+
- lib/redis_queued_locks/acquirer/lock_series/instr_visitor.rb
|
|
98
|
+
- lib/redis_queued_locks/acquirer/lock_series/log_visitor.rb
|
|
99
|
+
- lib/redis_queued_locks/acquirer/lock_series/release_lock_series.rb
|
|
100
|
+
- lib/redis_queued_locks/acquirer/lock_series/try_to_lock_series.rb
|
|
84
101
|
- lib/redis_queued_locks/acquirer/locks.rb
|
|
85
102
|
- lib/redis_queued_locks/acquirer/queue_info.rb
|
|
86
103
|
- lib/redis_queued_locks/acquirer/queues.rb
|
|
@@ -122,7 +139,7 @@ files:
|
|
|
122
139
|
- redis_queued_locks.gemspec
|
|
123
140
|
- sig/manifest.yml
|
|
124
141
|
- sig/redis_queued_locks.rbs
|
|
125
|
-
- sig/redis_queued_locks/
|
|
142
|
+
- sig/redis_queued_locks/acquirer.rbs
|
|
126
143
|
- sig/redis_queued_locks/acquirer/acquire_lock.rbs
|
|
127
144
|
- sig/redis_queued_locks/acquirer/acquire_lock/delay_execution.rbs
|
|
128
145
|
- sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue.rbs
|
|
@@ -133,13 +150,18 @@ files:
|
|
|
133
150
|
- sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rbs
|
|
134
151
|
- sig/redis_queued_locks/acquirer/acquire_lock/with_acq_timeout.rbs
|
|
135
152
|
- sig/redis_queued_locks/acquirer/acquire_lock/yield_expire.rbs
|
|
136
|
-
- sig/redis_queued_locks/acquirer/acquire_lock/
|
|
153
|
+
- sig/redis_queued_locks/acquirer/acquire_lock/yield_expire/log_visitor.rbs
|
|
137
154
|
- sig/redis_queued_locks/acquirer/clear_dead_requests.rbs
|
|
138
155
|
- sig/redis_queued_locks/acquirer/extend_lock_ttl.rbs
|
|
139
156
|
- sig/redis_queued_locks/acquirer/is_locked.rbs
|
|
140
157
|
- sig/redis_queued_locks/acquirer/is_queued.rbs
|
|
141
158
|
- sig/redis_queued_locks/acquirer/keys.rbs
|
|
142
159
|
- sig/redis_queued_locks/acquirer/lock_info.rbs
|
|
160
|
+
- sig/redis_queued_locks/acquirer/lock_series.rbs
|
|
161
|
+
- sig/redis_queued_locks/acquirer/lock_series/instr_visitor.rbs
|
|
162
|
+
- sig/redis_queued_locks/acquirer/lock_series/log_visitor.rbs
|
|
163
|
+
- sig/redis_queued_locks/acquirer/lock_series/release_lock_series.rbs
|
|
164
|
+
- sig/redis_queued_locks/acquirer/lock_series/try_to_lock_series.rbs
|
|
143
165
|
- sig/redis_queued_locks/acquirer/locks.rbs
|
|
144
166
|
- sig/redis_queued_locks/acquirer/queue_info.rbs
|
|
145
167
|
- sig/redis_queued_locks/acquirer/queues.rbs
|
|
@@ -200,7 +222,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
200
222
|
- !ruby/object:Gem::Version
|
|
201
223
|
version: '0'
|
|
202
224
|
requirements: []
|
|
203
|
-
rubygems_version: 4.0.
|
|
225
|
+
rubygems_version: 4.0.20
|
|
204
226
|
specification_version: 4
|
|
205
227
|
summary: Distributed locks with "prioritized lock acquisition queue" capabilities
|
|
206
228
|
based on the Redis Database.
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# NOTE: Lock Series PoC
|
|
4
|
-
# @api private
|
|
5
|
-
# @since 1.16.1
|
|
6
|
-
# @version 1.18.0
|
|
7
|
-
module RedisQueuedLocks::Acquirer::LockSeriesPoC::InstrVisitor # steep:ignore
|
|
8
|
-
class << self
|
|
9
|
-
# NOTE: Lock Series PoC
|
|
10
|
-
# @param rw_mode [Symbol] The mode of the lock series (`:read` or `:write`).
|
|
11
|
-
# @api private
|
|
12
|
-
# @since 1.16.1
|
|
13
|
-
# @version 1.18.0
|
|
14
|
-
def lock_series_obtained( # steep:ignore
|
|
15
|
-
instrumenter,
|
|
16
|
-
instr_sampled,
|
|
17
|
-
lock_keys,
|
|
18
|
-
rw_mode,
|
|
19
|
-
ttl,
|
|
20
|
-
acq_id,
|
|
21
|
-
hst_id,
|
|
22
|
-
ts,
|
|
23
|
-
acq_time,
|
|
24
|
-
instrument
|
|
25
|
-
)
|
|
26
|
-
return unless instr_sampled
|
|
27
|
-
instrumenter.notify('redis_queued_locks.lock_series_obtained', {
|
|
28
|
-
lock_keys:, rw_mode:, ttl:, acq_id:, hst_id:, ts:, acq_time:, instrument:
|
|
29
|
-
}) rescue nil
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# NOTE: Lock Series PoC
|
|
33
|
-
# @param rw_mode [Symbol] The mode of the lock series (`:read` or `:write`).
|
|
34
|
-
# @api private
|
|
35
|
-
# @since 1.16.1
|
|
36
|
-
# @version 1.21.0
|
|
37
|
-
def lock_series_hold_and_release( # steep:ignore
|
|
38
|
-
instrumenter,
|
|
39
|
-
instr_sampled,
|
|
40
|
-
lock_keys,
|
|
41
|
-
rw_mode,
|
|
42
|
-
ttl,
|
|
43
|
-
acq_id,
|
|
44
|
-
hst_id,
|
|
45
|
-
ts,
|
|
46
|
-
acq_time,
|
|
47
|
-
hold_time,
|
|
48
|
-
instrument
|
|
49
|
-
)
|
|
50
|
-
return unless instr_sampled
|
|
51
|
-
instrumenter.notify('redis_queued_locks.lock_series_hold_and_release', {
|
|
52
|
-
lock_keys:, rw_mode:, hold_time:, ttl:, acq_id:, hst_id:, ts:, acq_time:, instrument:
|
|
53
|
-
}) rescue nil
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# NOTE: Lock Series PoC
|
|
4
|
-
# @api private
|
|
5
|
-
# @since 1.16.1
|
|
6
|
-
# @version 1.18.0
|
|
7
|
-
module RedisQueuedLocks::Acquirer::LockSeriesPoC::LogVisitor # steep:ignore
|
|
8
|
-
class << self
|
|
9
|
-
# NOTE: Lock Series PoC
|
|
10
|
-
# @param rw_mode [Symbol] The mode of the lock series (`:read` or `:write`).
|
|
11
|
-
# @api private
|
|
12
|
-
# @since 1.16.0
|
|
13
|
-
# @version 1.21.0
|
|
14
|
-
def start_lock_series_obtaining( # steep:ignore
|
|
15
|
-
logger,
|
|
16
|
-
log_sampled,
|
|
17
|
-
lock_keys,
|
|
18
|
-
queue_ttl,
|
|
19
|
-
acquirer_id,
|
|
20
|
-
host_id,
|
|
21
|
-
access_strategy,
|
|
22
|
-
rw_mode
|
|
23
|
-
)
|
|
24
|
-
return unless log_sampled
|
|
25
|
-
|
|
26
|
-
logger.debug do
|
|
27
|
-
"[redis_queued_locks.start_lock_series_obtaining] " \
|
|
28
|
-
"lock_keys => '#{lock_keys.inspect}' " \
|
|
29
|
-
"queue_ttl => #{queue_ttl} " \
|
|
30
|
-
"acq_id => '#{acquirer_id}' " \
|
|
31
|
-
"hst_id => '#{host_id}' " \
|
|
32
|
-
"acs_strat => '#{access_strategy}' " \
|
|
33
|
-
"rw_mode => '#{rw_mode}'"
|
|
34
|
-
end rescue nil
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# NOTE: Lock Series PoC
|
|
38
|
-
# @param rw_mode [Symbol] The mode of the lock series (`:read` or `:write`).
|
|
39
|
-
# @api private
|
|
40
|
-
# @since 1.16.0
|
|
41
|
-
# @version 1.21.0
|
|
42
|
-
def lock_series_obtained( # steep:ignore
|
|
43
|
-
logger,
|
|
44
|
-
log_sampled,
|
|
45
|
-
lock_keys,
|
|
46
|
-
queue_ttl,
|
|
47
|
-
acquirer_id,
|
|
48
|
-
host_id,
|
|
49
|
-
acq_time,
|
|
50
|
-
access_strategy,
|
|
51
|
-
rw_mode
|
|
52
|
-
)
|
|
53
|
-
return unless log_sampled
|
|
54
|
-
|
|
55
|
-
logger.debug do
|
|
56
|
-
"[redis_queued_locks.lock_series_obtained] " \
|
|
57
|
-
"lock_keys => '#{lock_keys.inspect}' " \
|
|
58
|
-
"queue_ttl => #{queue_ttl} " \
|
|
59
|
-
"acq_id => '#{acquirer_id}' " \
|
|
60
|
-
"hst_id => '#{host_id}' " \
|
|
61
|
-
"acs_strat => '#{access_strategy}' " \
|
|
62
|
-
"rw_mode => '#{rw_mode}' " \
|
|
63
|
-
"acq_time => #{acq_time} (ms)"
|
|
64
|
-
end rescue nil
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# NOTE: Lock Series PoC
|
|
68
|
-
# @param rw_mode [Symbol] The mode of the lock series (`:read` or `:write`).
|
|
69
|
-
# @api private
|
|
70
|
-
# @since 1.16.0
|
|
71
|
-
# @version 1.18.0
|
|
72
|
-
def expire_lock_series( # steep:ignore
|
|
73
|
-
logger,
|
|
74
|
-
log_sampled,
|
|
75
|
-
lock_series,
|
|
76
|
-
queue_ttl,
|
|
77
|
-
acquirer_id,
|
|
78
|
-
host_id,
|
|
79
|
-
access_strategy,
|
|
80
|
-
rw_mode
|
|
81
|
-
)
|
|
82
|
-
return unless log_sampled
|
|
83
|
-
|
|
84
|
-
logger.debug do
|
|
85
|
-
"[redis_queued_locks.expire_lock_series] " \
|
|
86
|
-
"lock_keys => '#{lock_series.inspect}' " \
|
|
87
|
-
"queue_ttl => #{queue_ttl} " \
|
|
88
|
-
"acq_id => '#{acquirer_id}' " \
|
|
89
|
-
"hst_id => '#{host_id}' " \
|
|
90
|
-
"acs_strat => '#{access_strategy}' " \
|
|
91
|
-
"rw_mode => '#{rw_mode}'"
|
|
92
|
-
end rescue nil
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|