redis_queued_locks 1.19.0 → 1.20.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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/project-overview.md +62 -11
  3. data/.claude/rules/acquirer.md +29 -11
  4. data/.claude/rules/arguments.md +3 -2
  5. data/.claude/rules/git.md +3 -2
  6. data/.claude/rules/logic.md +4 -3
  7. data/.claude/rules/swarm.md +12 -7
  8. data/.claude/rules/tests.md +6 -0
  9. data/.claude/rules/type-checking.md +2 -1
  10. data/.claude/rules/visitors.md +1 -1
  11. data/.claude/skills/rql-code-review/SKILL.md +372 -0
  12. data/.claude/skills/rql-code-review/templates/report.en.md +31 -0
  13. data/.claude/skills/rql-code-review/templates/report.ru.md +31 -0
  14. data/CHANGELOG.md +68 -0
  15. data/CLAUDE.md +4 -2
  16. data/README.md +257 -22
  17. data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rb +684 -128
  18. data/lib/redis_queued_locks/acquirer/acquire_lock/yield_expire.rb +3 -1
  19. data/lib/redis_queued_locks/acquirer/acquire_lock.rb +24 -3
  20. data/lib/redis_queued_locks/acquirer/clear_dead_requests.rb +145 -18
  21. data/lib/redis_queued_locks/acquirer/extend_lock_ttl.rb +71 -10
  22. data/lib/redis_queued_locks/acquirer/keys.rb +142 -7
  23. data/lib/redis_queued_locks/acquirer/lock_info.rb +10 -4
  24. data/lib/redis_queued_locks/acquirer/lock_series_poc.rb +26 -7
  25. data/lib/redis_queued_locks/acquirer/locks.rb +195 -83
  26. data/lib/redis_queued_locks/acquirer/queue_info.rb +12 -18
  27. data/lib/redis_queued_locks/acquirer/queues.rb +114 -50
  28. data/lib/redis_queued_locks/acquirer/reindex_locks.rb +140 -0
  29. data/lib/redis_queued_locks/acquirer/release_all_locks.rb +147 -58
  30. data/lib/redis_queued_locks/acquirer/release_lock.rb +52 -19
  31. data/lib/redis_queued_locks/acquirer/release_locks_of.rb +235 -66
  32. data/lib/redis_queued_locks/acquirer.rb +1 -0
  33. data/lib/redis_queued_locks/client.rb +97 -11
  34. data/lib/redis_queued_locks/config.rb +5 -1
  35. data/lib/redis_queued_locks/resource.rb +99 -2
  36. data/lib/redis_queued_locks/swarm/flush_zombies.rb +332 -61
  37. data/lib/redis_queued_locks/swarm/zombie_info.rb +203 -53
  38. data/lib/redis_queued_locks/swarm.rb +15 -4
  39. data/lib/redis_queued_locks/version.rb +2 -2
  40. data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rbs +107 -1
  41. data/sig/redis_queued_locks/acquirer/acquire_lock/yield_expire.rbs +1 -1
  42. data/sig/redis_queued_locks/acquirer/acquire_lock.rbs +2 -0
  43. data/sig/redis_queued_locks/acquirer/clear_dead_requests.rbs +10 -1
  44. data/sig/redis_queued_locks/acquirer/extend_lock_ttl.rbs +5 -2
  45. data/sig/redis_queued_locks/acquirer/keys.rbs +11 -1
  46. data/sig/redis_queued_locks/acquirer/locks.rbs +15 -6
  47. data/sig/redis_queued_locks/acquirer/queues.rbs +9 -2
  48. data/sig/redis_queued_locks/acquirer/reindex_locks.rbs +31 -0
  49. data/sig/redis_queued_locks/acquirer/release_all_locks.rbs +8 -1
  50. data/sig/redis_queued_locks/acquirer/release_lock.rbs +3 -1
  51. data/sig/redis_queued_locks/acquirer/release_locks_of.rbs +20 -1
  52. data/sig/redis_queued_locks/client.rbs +8 -0
  53. data/sig/redis_queued_locks/resource.rbs +6 -0
  54. data/sig/redis_queued_locks/swarm/flush_zombies.rbs +51 -1
  55. data/sig/redis_queued_locks/swarm/zombie_info.rbs +58 -7
  56. data/sig/vendor/redis_client.rbs +1 -0
  57. metadata +6 -1
@@ -9,16 +9,25 @@ module RedisQueuedLocks
9
9
  type locksInfo = Set[{ lock: String, status: Symbol, info: lockInfo }]
10
10
  type locks = lockList | locksInfo
11
11
 
12
- def self.locks: (RC::client redis_client, scan_size: Integer, with_info: bool) -> locks
12
+ LOCK_STATE_REPLIES: Integer
13
+
14
+ def self.locks: (
15
+ RC::client redis_client,
16
+ scan_size: Integer,
17
+ with_info: bool,
18
+ lock_index_enabled: bool
19
+ ) -> locks
13
20
 
14
21
  private def self.scan_locks: (RC::client redis_client, Integer scan_size) -> lockList
15
- private def self.extract_locks_info: (RC::client redis_client, Set[::String] lock_keys) -> locksInfo
22
+ private def self.index_locks: (RC::client redis_client, Integer scan_size) -> lockList
23
+ private def self.each_lock_name_batch: (RC::client redis_client, Integer scan_size) { (Array[String] lock_names) -> void } -> void
24
+ private def self.extract_locks_info: (RC::client redis_client, Set[::String] lock_keys, Integer scan_size) -> locksInfo
16
25
  private def self.read_lock_info: (
17
- RC::client redis_client,
18
- String lock_name,
19
26
  String lock_key,
20
- Array[String] redis_time,
21
- Array[[String, Float]] read_locks
27
+ Integer now,
28
+ Array[[String, Float]] live_read_locks,
29
+ Array[Hash[String,String]] read_locks_data,
30
+ Integer read_locks_data_at
22
31
  ) -> lockInfo?
23
32
  end
24
33
  end
@@ -7,10 +7,17 @@ module RedisQueuedLocks
7
7
  type queuesInfo = Set[{ queue: String, requests: Array[Hash[String,String|Float]] }]
8
8
  type queues = queueList | queuesInfo
9
9
 
10
- def self.queues: (RC::client redis_client, scan_size: Integer, with_info: bool) -> queues
10
+ def self.queues: (
11
+ RC::client redis_client,
12
+ scan_size: Integer,
13
+ with_info: bool,
14
+ lock_index_enabled: bool
15
+ ) -> queues
11
16
 
12
17
  private def self.scan_queues: (RC::client redis_client, Integer scan_size) -> queueList
13
- private def self.extract_queues_info: (RC::client redis_client, Set[String] lock_queues) -> queuesInfo
18
+ private def self.index_queues: (RC::client redis_client, Integer scan_size) -> queueList
19
+ private def self.each_lock_name_batch: (RC::client redis_client, Integer scan_size) { (Array[String] lock_names) -> void } -> void
20
+ private def self.extract_queues_info: (RC::client redis_client, Set[String] lock_queues, Integer scan_size) -> queuesInfo
14
21
  end
15
22
  end
16
23
  end
@@ -0,0 +1,31 @@
1
+ use RedisClient as RC
2
+
3
+ module RedisQueuedLocks
4
+ module Acquirer
5
+ module ReindexLocks
6
+ type reindexResult = { ok: bool, result: { idx_key_cnt: Integer } }
7
+ def self.reindex_locks: (
8
+ RC::client redis_client,
9
+ Integer scan_size,
10
+ Integer queue_ttl,
11
+ Integer lock_index_grace_period
12
+ ) -> reindexResult
13
+
14
+ private def self.index_lock_keys: (
15
+ RC::client redis_client,
16
+ Array[String] lock_keys,
17
+ Array[String] lock_queues,
18
+ Integer queue_pttl,
19
+ Integer lock_index_grace_period
20
+ ) -> Integer
21
+
22
+ private def self.index_lock_key: (
23
+ RedisClient::Pipeline pipeline,
24
+ String key,
25
+ Integer key_ttl,
26
+ Integer lock_index_time,
27
+ Integer lock_index_grace_period
28
+ ) -> Integer
29
+ end
30
+ end
31
+ end
@@ -10,6 +10,7 @@ module RedisQueuedLocks
10
10
  def self.release_all_locks: (
11
11
  RC::client redis,
12
12
  Integer batch_size,
13
+ bool lock_index_enabled,
13
14
  RQL::loggerObj logger,
14
15
  RQL::instrObj instrumenter,
15
16
  untyped instrument,
@@ -24,7 +25,13 @@ module RedisQueuedLocks
24
25
  ) -> releaseResult
25
26
 
26
27
  type fullRelesaeResult = { ok: bool, result: { rel_key_cnt: Integer } }
27
- private def self.fully_release_all_locks: (RC::client redis, Integer batch_size) -> fullRelesaeResult
28
+ private def self.fully_release_all_locks: (
29
+ RC::client redis,
30
+ Integer batch_size,
31
+ bool lock_index_enabled
32
+ ) -> fullRelesaeResult
33
+ private def self.release_locks: (RC::client redis_client, Array[String] lock_names) -> Integer
34
+ private def self.each_lock_name_batch: (RC::client redis_client, Integer scan_size) { (Array[String] lock_names) -> void } -> void
28
35
  end
29
36
  end
30
37
  end
@@ -19,6 +19,7 @@ module RedisQueuedLocks
19
19
  def self.release_lock: (
20
20
  RC::client redis,
21
21
  String lock_name,
22
+ bool lock_index_enabled,
22
23
  RQL::instrObj instrumenter,
23
24
  RQL::loggerObj logger,
24
25
  bool log_sampling_enabled,
@@ -38,7 +39,8 @@ module RedisQueuedLocks
38
39
  String lock_key,
39
40
  String lock_key_queue,
40
41
  String read_lock_key_queue,
41
- String lock_readers_key
42
+ String lock_readers_key,
43
+ bool lock_index_enabled
42
44
  ) -> fullReleaseResult
43
45
  end
44
46
  end
@@ -20,6 +20,7 @@ module RedisQueuedLocks
20
20
  RC::client redis,
21
21
  Integer lock_scan_size,
22
22
  Integer queue_scan_size,
23
+ bool lock_index_enabled,
23
24
  RQL::loggerObj logger,
24
25
  RQL::instrObj instrumenter,
25
26
  untyped instrument,
@@ -39,8 +40,26 @@ module RedisQueuedLocks
39
40
  String refused_acquirer_id,
40
41
  RC::client redis,
41
42
  Integer locks_scan_size,
42
- Integer queue_scan_size
43
+ Integer queue_scan_size,
44
+ bool lock_index_enabled
43
45
  ) -> fullyReleaseAllLocksResult
46
+ private def self.release_refused_locks: (
47
+ RC::client redis_client,
48
+ Array[String] lock_keys,
49
+ String refused_host_id,
50
+ String refused_acquirer_id
51
+ ) -> Integer
52
+ private def self.release_refused_read_locks: (
53
+ RC::client redis_client,
54
+ Array[String] lock_readers_keys,
55
+ String refused_acquirer_id
56
+ ) -> Integer
57
+ private def self.dequeue_refused_acquirer: (
58
+ RC::client redis_client,
59
+ Array[String] lock_queues,
60
+ String refused_acquirer_id
61
+ ) -> Integer
62
+ private def self.each_lock_name_batch: (RC::client redis_client, Integer scan_size) { (Array[String] lock_names) -> void } -> void
44
63
  end
45
64
  end
46
65
  end
@@ -36,6 +36,7 @@ module RedisQueuedLocks
36
36
  String lock_name,
37
37
  ?ttl: Integer,
38
38
  ?queue_ttl: Integer,
39
+ ?lock_index_grace_period: Integer,
39
40
  ?timeout: Integer?,
40
41
  ?timed: bool,
41
42
  ?retry_count: Integer?,
@@ -67,6 +68,7 @@ module RedisQueuedLocks
67
68
  String lock_name,
68
69
  ?ttl: Integer,
69
70
  ?queue_ttl: Integer,
71
+ ?lock_index_grace_period: Integer,
70
72
  ?timeout: Integer?,
71
73
  ?timed: bool,
72
74
  ?retry_count: Integer?,
@@ -252,5 +254,11 @@ module RedisQueuedLocks
252
254
  ?instr_sampler: RQL::Instrument::samplerObj,
253
255
  ?instr_sample_this: bool
254
256
  ) -> RQL::Acquirer::ClearDeadRequests::clearResult
257
+
258
+ def reindex_locks: (
259
+ ?scan_size: Integer,
260
+ ?queue_ttl: Integer,
261
+ ?lock_index_grace_period: Integer
262
+ ) -> RQL::Acquirer::ReindexLocks::reindexResult
255
263
  end
256
264
  end
@@ -6,7 +6,9 @@ module RedisQueuedLocks
6
6
  READ_LOCK_QUEUE_PATTERN: String
7
7
  LOCK_READERS_PATTERN: String
8
8
  READ_LOCK_PATTERN: String
9
+ ALL_LOCK_QUEUES_PATTERN: String
9
10
  SWARM_KEY: String
11
+ LOCK_INDEX_KEY: String
10
12
  REDIS_TIMESHIFT_ERROR: Integer
11
13
 
12
14
  def self.calc_uniq_identity: () -> String
@@ -31,6 +33,10 @@ module RedisQueuedLocks
31
33
  def self.prepare_lock_readers: (String lock_name) -> String
32
34
  def self.prepare_read_lock_key: (String lock_name, String acquirer_id) -> String
33
35
  def self.lock_queue_rw_mode: (String lock_queue) -> String?
36
+ type lockKeyFamily = :lock | :lock_queue | :lock_readers | :read_lock_queue | :read_lock
37
+ def self.lock_key_family: (String key) -> lockKeyFamily?
38
+ def self.lock_name_from_key: (String key, lockKeyFamily? key_family) -> String?
39
+ def self.lock_index_time: () -> Integer
34
40
  def self.lock_name_from_readers: (String lock_readers_key) -> String
35
41
  def self.lock_key_from_readers: (String lock_readers_key) -> String
36
42
  def self.host_identifier_from_acquirer: (String acquirer_id) -> String
@@ -4,7 +4,57 @@ module RedisQueuedLocks
4
4
  class Swarm
5
5
  class FlushZombies < SwarmElement::Isolated
6
6
  type flushedZombies = { ok: bool, deleted_zombie_hosts: Set[String], deleted_zombie_acquirers: Set[String], deleted_zombie_locks: Set[String] }
7
- def self.flush_zombies: (RC::client redis_client, Integer zombie_ttl, Integer lock_scan_size, Integer queue_scan_size) -> flushedZombies
7
+ def self.flush_zombies: (
8
+ RC::client redis_client,
9
+ Integer zombie_ttl,
10
+ Integer lock_scan_size,
11
+ Integer queue_scan_size,
12
+ bool lock_index_enabled
13
+ ) -> flushedZombies
14
+ private def self.flush_keyspace_zombies: (
15
+ RC::client rconn,
16
+ Set[String] zombie_hosts,
17
+ Integer lock_scan_size,
18
+ Integer queue_scan_size,
19
+ Set[String] zombie_locks,
20
+ Set[String] zombie_acquirers
21
+ ) -> void
22
+ private def self.flush_lock_index_zombies: (
23
+ RC::client rconn,
24
+ Set[String] zombie_hosts,
25
+ Integer lock_scan_size,
26
+ Integer queue_scan_size,
27
+ Set[String] zombie_locks,
28
+ Set[String] zombie_acquirers
29
+ ) -> void
30
+ private def self.batch_zombie_requests: (
31
+ RC::client redis_client,
32
+ Array[String] lock_queues,
33
+ String lock_queue,
34
+ Integer queue_scan_size,
35
+ Set[String] zombie_hosts,
36
+ Set[String] zombie_acquirers
37
+ ) -> void
38
+ private def self.flush_zombie_locks: (
39
+ RC::client redis_client,
40
+ Array[String] lock_keys,
41
+ Set[String] zombie_hosts,
42
+ Set[String] zombie_locks,
43
+ Set[String] zombie_acquirers
44
+ ) -> void
45
+ private def self.flush_zombie_read_locks: (
46
+ RC::client redis_client,
47
+ Array[String] lock_readers_keys,
48
+ Set[String] zombie_hosts,
49
+ Set[String] zombie_locks,
50
+ Set[String] zombie_acquirers
51
+ ) -> void
52
+ private def self.flush_zombie_requests: (
53
+ RC::client redis_client,
54
+ Array[String] lock_queues,
55
+ Set[String] zombie_hosts,
56
+ Set[String] zombie_acquirers
57
+ ) -> void
8
58
 
9
59
  def enabled?: () -> bool
10
60
  def spawn_swarm_element!: (Ractor::Port[SwarmElement::Isolated::resultsPortMessage] swarm_element_results_port) -> Ractor
@@ -4,25 +4,76 @@ module RedisQueuedLocks
4
4
  class Swarm
5
5
  module ZombieInfo
6
6
  type zombieInfo = { zombie_hosts: Set[String], zombie_acquirers: Set[String], zombie_locks: Set[String] }
7
- def self.zombies_info: (RC::client redis_client, Integer zombie_ttl, Integer lock_scan_size) -> zombieInfo
7
+ def self.zombies_info: (
8
+ RC::client redis_client,
9
+ Integer zombie_ttl,
10
+ Integer lock_scan_size,
11
+ bool lock_index_enabled
12
+ ) -> zombieInfo
8
13
 
9
14
  type zombieLocks = Set[String]
10
- def self.zombie_locks: (RC::client redis_client, Integer zombie_ttl, Integer lock_scan_size) -> zombieLocks
15
+ def self.zombie_locks: (
16
+ RC::client redis_client,
17
+ Integer zombie_ttl,
18
+ Integer lock_scan_size,
19
+ bool lock_index_enabled
20
+ ) -> zombieLocks
11
21
 
12
22
  type zombieHosts = Set[String]
13
23
  def self.zombie_hosts: (RC::client redis_client, Integer zombie_ttl) -> zombieHosts
14
24
 
15
25
  type zombieAcquirers = Set[String]
16
- def self.zombie_acquirers: (RC::client redis_client, Integer zombie_ttl, Integer lock_scan_size) -> zombieAcquirers
26
+ def self.zombie_acquirers: (
27
+ RC::client redis_client,
28
+ Integer zombie_ttl,
29
+ Integer lock_scan_size,
30
+ bool lock_index_enabled
31
+ ) -> zombieAcquirers
17
32
 
18
33
  private def self.extract_zombie_hosts: (RC::client rconn, Integer zombie_ttl) -> zombieHosts
19
- private def self.extract_zombie_locks: (RC::client rconn, Integer zombie_ttl, Integer lock_scan_size) -> zombieLocks
20
- private def self.extract_zombie_acquirers: (RC::client rconn, Integer zombie_ttl, Integer lock_scan_size) -> zombieAcquirers
21
- private def self.extract_all: (RC::client rconn, Integer zombie_ttl, Integer lock_scan_size) -> zombieInfo
22
- private def self.each_zombie_read_lock: (
34
+ private def self.extract_zombie_locks: (
35
+ RC::client rconn,
36
+ Integer zombie_ttl,
37
+ Integer lock_scan_size,
38
+ bool lock_index_enabled
39
+ ) -> zombieLocks
40
+ private def self.extract_zombie_acquirers: (
41
+ RC::client rconn,
42
+ Integer zombie_ttl,
43
+ Integer lock_scan_size,
44
+ bool lock_index_enabled
45
+ ) -> zombieAcquirers
46
+ private def self.extract_all: (
47
+ RC::client rconn,
48
+ Integer zombie_ttl,
49
+ Integer lock_scan_size,
50
+ bool lock_index_enabled
51
+ ) -> zombieInfo
52
+ private def self.each_zombie_lock: (
53
+ RC::client rconn,
54
+ Set[String] zombie_hosts,
55
+ Integer lock_scan_size,
56
+ bool lock_index_enabled
57
+ ) { (String lock_key, String acquirer_id) -> void } -> void
58
+ private def self.each_keyspace_zombie_lock: (
23
59
  RC::client rconn,
24
60
  Set[String] zombie_hosts,
25
61
  Integer lock_scan_size
62
+ ) { (String lock_key, String acquirer_id) -> void } -> void
63
+ private def self.each_lock_index_zombie_lock: (
64
+ RC::client rconn,
65
+ Set[String] zombie_hosts,
66
+ Integer lock_scan_size
67
+ ) { (String lock_key, String acquirer_id) -> void } -> void
68
+ private def self.each_zombie_write_lock: (
69
+ RC::client rconn,
70
+ Array[String] lock_keys,
71
+ Set[String] zombie_hosts
72
+ ) { (String lock_key, String acquirer_id) -> void } -> void
73
+ private def self.each_zombie_read_lock: (
74
+ RC::client rconn,
75
+ Array[String] lock_readers_keys,
76
+ Set[String] zombie_hosts
26
77
  ) { (String lock_readers_key, String acquirer_id) -> void } -> void
27
78
  end
28
79
  end
@@ -3,6 +3,7 @@ class RedisClient
3
3
  def call: (*untyped) -> untyped
4
4
  def pipelined: () { (Pipeline pipeline) -> untyped } -> untyped
5
5
  def scan: (*untyped) { (String key) -> untyped } -> untyped
6
+ def zscan: (String key, *untyped) { (String member, String score) -> untyped } -> untyped
6
7
  def multi: (?watch: Array[String]) { (Multi transact) -> untyped } -> untyped
7
8
  def with: (?untyped) { (::RedisClient|::RedisClient::Pooled rconn) -> untyped } -> untyped
8
9
  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.19.0
4
+ version: 1.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rustam Ibragimov
@@ -44,6 +44,9 @@ files:
44
44
  - ".claude/rules/tests.md"
45
45
  - ".claude/rules/type-checking.md"
46
46
  - ".claude/rules/visitors.md"
47
+ - ".claude/skills/rql-code-review/SKILL.md"
48
+ - ".claude/skills/rql-code-review/templates/report.en.md"
49
+ - ".claude/skills/rql-code-review/templates/report.ru.md"
47
50
  - ".rspec"
48
51
  - ".rubocop.rbs.yml"
49
52
  - ".rubocop.yml"
@@ -81,6 +84,7 @@ files:
81
84
  - lib/redis_queued_locks/acquirer/locks.rb
82
85
  - lib/redis_queued_locks/acquirer/queue_info.rb
83
86
  - lib/redis_queued_locks/acquirer/queues.rb
87
+ - lib/redis_queued_locks/acquirer/reindex_locks.rb
84
88
  - lib/redis_queued_locks/acquirer/release_all_locks.rb
85
89
  - lib/redis_queued_locks/acquirer/release_lock.rb
86
90
  - lib/redis_queued_locks/acquirer/release_locks_of.rb
@@ -139,6 +143,7 @@ files:
139
143
  - sig/redis_queued_locks/acquirer/locks.rbs
140
144
  - sig/redis_queued_locks/acquirer/queue_info.rbs
141
145
  - sig/redis_queued_locks/acquirer/queues.rbs
146
+ - sig/redis_queued_locks/acquirer/reindex_locks.rbs
142
147
  - sig/redis_queued_locks/acquirer/release_all_locks.rbs
143
148
  - sig/redis_queued_locks/acquirer/release_lock.rbs
144
149
  - sig/redis_queued_locks/acquirer/release_locks_of.rbs