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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/project-overview.md +294 -51
  3. data/.claude/rules/acquirer.md +16 -11
  4. data/.claude/rules/arguments.md +2 -2
  5. data/.claude/rules/changelog.md +27 -0
  6. data/.claude/rules/git.md +1 -1
  7. data/.claude/rules/logic.md +14 -15
  8. data/.claude/rules/swarm.md +3 -4
  9. data/.claude/rules/tests.md +9 -9
  10. data/.claude/rules/type-checking.md +14 -16
  11. data/.claude/rules/visitors.md +11 -9
  12. data/.claude/skills/rql-code-review/SKILL.md +129 -47
  13. data/.ruby-version +1 -1
  14. data/CHANGELOG.md +122 -245
  15. data/CLAUDE.md +12 -10
  16. data/README.md +516 -175
  17. data/Rakefile +11 -0
  18. data/lib/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue.rb +4 -4
  19. data/lib/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rb +28 -12
  20. data/lib/redis_queued_locks/acquirer/acquire_lock/log_visitor.rb +38 -16
  21. data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rb +92 -15
  22. data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rb +945 -272
  23. data/lib/redis_queued_locks/acquirer/acquire_lock.rb +82 -32
  24. data/lib/redis_queued_locks/acquirer/clear_dead_requests.rb +240 -45
  25. data/lib/redis_queued_locks/acquirer/extend_lock_ttl.rb +15 -13
  26. data/lib/redis_queued_locks/acquirer/keys.rb +6 -2
  27. data/lib/redis_queued_locks/acquirer/lock_series/instr_visitor.rb +243 -0
  28. data/lib/redis_queued_locks/acquirer/lock_series/log_visitor.rb +472 -0
  29. data/lib/redis_queued_locks/acquirer/lock_series/release_lock_series.rb +181 -0
  30. data/lib/redis_queued_locks/acquirer/lock_series/try_to_lock_series.rb +1051 -0
  31. data/lib/redis_queued_locks/acquirer/lock_series.rb +948 -0
  32. data/lib/redis_queued_locks/acquirer/locks.rb +6 -2
  33. data/lib/redis_queued_locks/acquirer/queue_info.rb +30 -7
  34. data/lib/redis_queued_locks/acquirer/queues.rb +17 -6
  35. data/lib/redis_queued_locks/acquirer/release_all_locks.rb +6 -2
  36. data/lib/redis_queued_locks/acquirer/release_locks_of.rb +6 -2
  37. data/lib/redis_queued_locks/acquirer.rb +1 -1
  38. data/lib/redis_queued_locks/client.rb +116 -44
  39. data/lib/redis_queued_locks/config.rb +93 -1
  40. data/lib/redis_queued_locks/resource.rb +124 -9
  41. data/lib/redis_queued_locks/swarm/swarm_element/threaded.rb +6 -5
  42. data/lib/redis_queued_locks/swarm/zombie_info.rb +6 -2
  43. data/lib/redis_queued_locks/version.rb +2 -2
  44. data/rbs_collection.lock.yaml +4 -0
  45. data/rbs_collection.yaml +2 -1
  46. data/redis_queued_locks.gemspec +21 -14
  47. data/sig/manifest.yml +1 -0
  48. data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rbs +2 -2
  49. data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue.rbs +2 -2
  50. data/sig/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rbs +12 -6
  51. data/sig/redis_queued_locks/acquirer/acquire_lock/log_visitor.rbs +21 -14
  52. data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rbs +61 -40
  53. data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rbs +160 -11
  54. data/sig/redis_queued_locks/acquirer/acquire_lock/{yield_with_expire → yield_expire}/log_visitor.rbs +4 -4
  55. data/sig/redis_queued_locks/acquirer/acquire_lock/yield_expire.rbs +2 -2
  56. data/sig/redis_queued_locks/acquirer/acquire_lock.rbs +5 -3
  57. data/sig/redis_queued_locks/acquirer/clear_dead_requests.rbs +14 -1
  58. data/sig/redis_queued_locks/acquirer/extend_lock_ttl.rbs +2 -2
  59. data/sig/redis_queued_locks/acquirer/lock_series/instr_visitor.rbs +102 -0
  60. data/sig/redis_queued_locks/acquirer/lock_series/log_visitor.rbs +154 -0
  61. data/sig/redis_queued_locks/acquirer/lock_series/release_lock_series.rbs +37 -0
  62. data/sig/redis_queued_locks/acquirer/lock_series/try_to_lock_series.rbs +198 -0
  63. data/sig/redis_queued_locks/acquirer/lock_series.rbs +106 -0
  64. data/sig/redis_queued_locks/acquirer/queues.rbs +1 -1
  65. data/sig/redis_queued_locks/client.rbs +77 -7
  66. data/sig/redis_queued_locks/config.rbs +54 -1
  67. data/sig/redis_queued_locks/instrument/sampler.rbs +3 -1
  68. data/sig/redis_queued_locks/instrument/void_notifier.rbs +3 -1
  69. data/sig/redis_queued_locks/logging/sampler.rbs +3 -1
  70. data/sig/redis_queued_locks/resource.rbs +22 -12
  71. data/sig/redis_queued_locks/swarm/swarm_element/threaded.rbs +1 -1
  72. data/sig/redis_queued_locks/utilities.rbs +2 -1
  73. data/sig/redis_queued_locks.rbs +7 -0
  74. metadata +35 -13
  75. data/lib/redis_queued_locks/acquirer/lock_series_poc/instr_visitor.rb +0 -56
  76. data/lib/redis_queued_locks/acquirer/lock_series_poc/log_visitor.rb +0 -95
  77. data/lib/redis_queued_locks/acquirer/lock_series_poc.rb +0 -484
  78. /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: Symbol,
48
- ?read_write_mode: :read | :write,
49
- ?access_strategy: Symbol,
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: Symbol,
79
- ?read_write_mode: :read | :write,
80
- ?access_strategy: Symbol,
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
- ?read_write_mode: :read | :write,
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
- def []: (String config_key) -> untyped
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
- def self.sampling_happened?: (Integer sampling_percent) -> bool
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
- def self.notify: (String event, ?Hash[untyped,untyped] payload) -> void
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
- def self.sampling_happened?: (Integer sampling_percent) -> bool
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
- def self.prepare_lock_key: (String lock_name) -> String
31
- def self.prepare_lock_queue: (String lock_name) -> String
32
- def self.prepare_read_lock_queue: (String lock_name) -> String
33
- def self.prepare_lock_readers: (String lock_name) -> String
34
- def self.prepare_read_lock_key: (String lock_name, String acquirer_id) -> String
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.lock_name_from_readers: (String lock_readers_key) -> String
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.calc_zombie_score: (Float zombie_ttl) -> Float
47
- def self.dead_score_reached?: (Float acquirer_position, Integer queue_ttl) -> bool
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 swarm_element__termiante: () -> void
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
- def self?.thread_state: (Thread thread) -> String
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
@@ -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.21.0
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
- |> Distributed locks with "prioritized lock acquisition queue" capabilities based on the Redis Database.
28
- |> Each lock request is put into the request queue (each lock is hosted by its own queue separately from other queues) and processed in order of their priority (FIFO).
29
- |> Each lock request lives some period of time (RTTL) (with requeue capabilities) which guarantees the request queue will never be stacked.
30
- |> In addition to the classic `queued` (FIFO) strategy RQL supports `random` (RANDOM) lock obtaining strategy when any acquirer from the lock queue can obtain the lock regardless the position in the queue.
31
- |> Provides flexible invocation flow, parametrized limits (lock request ttl, lock ttl, queue ttl, lock attempts limit, fast failing, etc), logging and instrumentation.
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/lock_series_poc.rb
82
- - lib/redis_queued_locks/acquirer/lock_series_poc/instr_visitor.rb
83
- - lib/redis_queued_locks/acquirer/lock_series_poc/log_visitor.rb
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/acquier.rbs
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/yield_with_expire/log_visitor.rbs
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.22
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