redis_queued_locks 1.12.0 → 1.13.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 (121) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -1
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +42 -5
  5. data/LICENSE.txt +1 -1
  6. data/README.md +231 -203
  7. data/Rakefile +12 -4
  8. data/Steepfile +16 -0
  9. data/github_ci/ruby3.3.gemfile +17 -0
  10. data/github_ci/ruby3.3.gemfile.lock +217 -0
  11. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/delay_execution.rb +4 -4
  12. data/lib/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +40 -0
  13. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/dequeue_from_lock_queue.rb +17 -8
  14. data/lib/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rb +166 -0
  15. data/lib/redis_queued_locks/acquirer/acquire_lock/log_visitor.rb +218 -0
  16. data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rb +543 -0
  17. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/try_to_lock.rb +126 -92
  18. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/with_acq_timeout.rb +14 -13
  19. data/lib/redis_queued_locks/acquirer/acquire_lock/yield_expire/log_visitor.rb +76 -0
  20. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/yield_expire.rb +43 -20
  21. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock.rb +69 -42
  22. data/lib/redis_queued_locks/{acquier → acquirer}/clear_dead_requests.rb +5 -3
  23. data/lib/redis_queued_locks/{acquier → acquirer}/extend_lock_ttl.rb +4 -3
  24. data/lib/redis_queued_locks/{acquier → acquirer}/is_locked.rb +1 -1
  25. data/lib/redis_queued_locks/{acquier → acquirer}/is_queued.rb +1 -1
  26. data/lib/redis_queued_locks/{acquier → acquirer}/keys.rb +5 -5
  27. data/lib/redis_queued_locks/{acquier → acquirer}/lock_info.rb +9 -5
  28. data/lib/redis_queued_locks/{acquier → acquirer}/locks.rb +16 -3
  29. data/lib/redis_queued_locks/{acquier → acquirer}/queue_info.rb +8 -6
  30. data/lib/redis_queued_locks/{acquier → acquirer}/queues.rb +9 -2
  31. data/lib/redis_queued_locks/{acquier → acquirer}/release_all_locks.rb +23 -18
  32. data/lib/redis_queued_locks/{acquier → acquirer}/release_lock.rb +25 -19
  33. data/lib/redis_queued_locks/acquirer.rb +18 -0
  34. data/lib/redis_queued_locks/client.rb +164 -254
  35. data/lib/redis_queued_locks/config/dsl.rb +94 -0
  36. data/lib/redis_queued_locks/config.rb +231 -0
  37. data/lib/redis_queued_locks/data.rb +2 -0
  38. data/lib/redis_queued_locks/errors.rb +27 -11
  39. data/lib/redis_queued_locks/instrument.rb +11 -4
  40. data/lib/redis_queued_locks/logging/void_logger.rb +38 -1
  41. data/lib/redis_queued_locks/logging.rb +20 -5
  42. data/lib/redis_queued_locks/resource.rb +49 -11
  43. data/lib/redis_queued_locks/swarm/acquirers.rb +17 -16
  44. data/lib/redis_queued_locks/swarm/flush_zombies.rb +26 -25
  45. data/lib/redis_queued_locks/swarm/probe_hosts.rb +20 -19
  46. data/lib/redis_queued_locks/swarm/redis_client_builder.rb +3 -3
  47. data/lib/redis_queued_locks/swarm/supervisor.rb +19 -6
  48. data/lib/redis_queued_locks/swarm/swarm_element/isolated.rb +20 -18
  49. data/lib/redis_queued_locks/swarm/swarm_element/threaded.rb +35 -27
  50. data/lib/redis_queued_locks/swarm/zombie_info.rb +9 -9
  51. data/lib/redis_queued_locks/swarm.rb +20 -41
  52. data/lib/redis_queued_locks/utilities/lock.rb +4 -2
  53. data/lib/redis_queued_locks/utilities.rb +2 -2
  54. data/lib/redis_queued_locks/version.rb +2 -2
  55. data/lib/redis_queued_locks.rb +2 -2
  56. data/rbs_collection.lock.yaml +40 -0
  57. data/rbs_collection.yaml +16 -0
  58. data/redis_queued_locks.gemspec +22 -23
  59. data/sig/manifest.yml +7 -0
  60. data/sig/redis_queued_locks/acquier.rbs +4 -0
  61. data/sig/redis_queued_locks/acquirer/acquire_lock/delay_execution.rbs +9 -0
  62. data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rbs +21 -0
  63. data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue.rbs +26 -0
  64. data/sig/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rbs +71 -0
  65. data/sig/redis_queued_locks/acquirer/acquire_lock/log_visitor.rbs +72 -0
  66. data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rbs +179 -0
  67. data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rbs +48 -0
  68. data/sig/redis_queued_locks/acquirer/acquire_lock/with_acq_timeout.rbs +19 -0
  69. data/sig/redis_queued_locks/acquirer/acquire_lock/yield_expire.rbs +41 -0
  70. data/sig/redis_queued_locks/acquirer/acquire_lock/yield_with_expire/log_visitor.rbs +32 -0
  71. data/sig/redis_queued_locks/acquirer/acquire_lock.rbs +51 -0
  72. data/sig/redis_queued_locks/acquirer/clear_dead_requests.rbs +28 -0
  73. data/sig/redis_queued_locks/acquirer/extend_lock_ttl.rbs +28 -0
  74. data/sig/redis_queued_locks/acquirer/is_locked.rbs +9 -0
  75. data/sig/redis_queued_locks/acquirer/is_queued.rbs +9 -0
  76. data/sig/redis_queued_locks/acquirer/keys.rbs +10 -0
  77. data/sig/redis_queued_locks/acquirer/lock_info.rbs +10 -0
  78. data/sig/redis_queued_locks/acquirer/locks.rbs +16 -0
  79. data/sig/redis_queued_locks/acquirer/queue_info.rbs +13 -0
  80. data/sig/redis_queued_locks/acquirer/queues.rbs +16 -0
  81. data/sig/redis_queued_locks/acquirer/release_all_locks.rbs +30 -0
  82. data/sig/redis_queued_locks/acquirer/release_lock.rbs +38 -0
  83. data/sig/redis_queued_locks/client.rbs +195 -0
  84. data/sig/redis_queued_locks/config/dsl.rbs +26 -0
  85. data/sig/redis_queued_locks/config.rbs +23 -0
  86. data/sig/redis_queued_locks/data.rbs +4 -0
  87. data/sig/redis_queued_locks/debugger/interface.rbs +9 -0
  88. data/sig/redis_queued_locks/debugger.rbs +13 -0
  89. data/sig/redis_queued_locks/errors.rbs +43 -0
  90. data/sig/redis_queued_locks/instrument/active_support.rbs +7 -0
  91. data/sig/redis_queued_locks/instrument/sampler.rbs +9 -0
  92. data/sig/redis_queued_locks/instrument/void_notifier.rbs +7 -0
  93. data/sig/redis_queued_locks/instrument.rbs +15 -0
  94. data/sig/redis_queued_locks/logging/sampler.rbs +9 -0
  95. data/sig/redis_queued_locks/logging/void_logger.rbs +15 -0
  96. data/sig/redis_queued_locks/logging.rbs +15 -0
  97. data/sig/redis_queued_locks/resource.rbs +42 -0
  98. data/sig/redis_queued_locks/swarm/acquirers.rbs +10 -0
  99. data/sig/redis_queued_locks/swarm/flush_zombies.rbs +13 -0
  100. data/sig/redis_queued_locks/swarm/probe_hosts.rbs +13 -0
  101. data/sig/redis_queued_locks/swarm/redis_client_builder.rbs +19 -0
  102. data/sig/redis_queued_locks/swarm/supervisor.rbs +26 -0
  103. data/sig/redis_queued_locks/swarm/swarm_element/isolated.rbs +52 -0
  104. data/sig/redis_queued_locks/swarm/swarm_element/threaded.rbs +61 -0
  105. data/sig/redis_queued_locks/swarm/swarm_element.rbs +8 -0
  106. data/sig/redis_queued_locks/swarm/zombie_info.rbs +24 -0
  107. data/sig/redis_queued_locks/swarm.rbs +41 -0
  108. data/sig/redis_queued_locks/utilities/lock.rbs +10 -0
  109. data/sig/redis_queued_locks/utilities.rbs +11 -0
  110. data/sig/redis_queued_locks/version.rbs +3 -0
  111. data/sig/redis_queued_locks.rbs +14 -0
  112. data/sig/vendor/active_support.rbs +9 -0
  113. data/sig/vendor/redis_client.rbs +39 -0
  114. data/sig/vendor/semantic_logger.rbs +4 -0
  115. metadata +96 -54
  116. data/lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +0 -40
  117. data/lib/redis_queued_locks/acquier/acquire_lock/instr_visitor.rb +0 -166
  118. data/lib/redis_queued_locks/acquier/acquire_lock/log_visitor.rb +0 -216
  119. data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock/log_visitor.rb +0 -541
  120. data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire/log_visitor.rb +0 -76
  121. data/lib/redis_queued_locks/acquier.rb +0 -18
@@ -21,6 +21,18 @@ module RedisQueuedLocks::Resource
21
21
  # @since 1.0.0
22
22
  LOCK_QUEUE_PATTERN = 'rql:lock_queue:*'
23
23
 
24
+ # @return [String]
25
+ #
26
+ # @api private
27
+ # @since ?.?.?
28
+ READ_LOCK_QUEUE_PATTERN = 'rql:lock_queue:*:read'
29
+
30
+ # @return [String]
31
+ #
32
+ # @api private
33
+ # @since ?.?.?
34
+ WRITE_LOCK_QUEUE_PATTERN = 'rql:lock_queue:*:write'
35
+
24
36
  # @return [String]
25
37
  #
26
38
  # @api private
@@ -55,7 +67,7 @@ module RedisQueuedLocks::Resource
55
67
  #
56
68
  # @api private
57
69
  # @since 1.0.0
58
- def acquier_identifier(process_id, thread_id, fiber_id, ractor_id, identity)
70
+ def acquirer_identifier(process_id, thread_id, fiber_id, ractor_id, identity)
59
71
  "rql:acq:#{process_id}/#{thread_id}/#{fiber_id}/#{ractor_id}/#{identity}"
60
72
  end
61
73
 
@@ -93,20 +105,38 @@ module RedisQueuedLocks::Resource
93
105
  "rql:lock_queue:#{lock_name}"
94
106
  end
95
107
 
108
+ # @param lock_name [String]
109
+ # @return [String]
110
+ #
111
+ # @api private
112
+ # @api ?.?.?
113
+ def prepare_read_lock_queue(lock_name)
114
+ "rql:lock_queue:#{lock_name}:read"
115
+ end
116
+
117
+ # @param lock_name [String]
118
+ # @return [String]
119
+ #
120
+ # @api private
121
+ # @api ?.?.?
122
+ def prepare_write_lock_queue(lock_name)
123
+ "rql:lock_queue:#{lock_name}:write"
124
+ end
125
+
96
126
  # @return [Float] Redis's <Set> score that is calculated from the time (epoch) as a float.
97
127
  #
98
128
  # @api private
99
129
  # @since 1.0.0
100
- def calc_initial_acquier_position
130
+ def calc_initial_acquirer_position
101
131
  Time.now.to_f
102
132
  end
103
133
 
104
- # @param queue_ttl [Integer] In seconds
105
- # @return [Float] Redis's <Set> score barrier for acquiers that should be removed from queue.
134
+ # @param queue_ttl [Numeric] In seconds
135
+ # @return [Float] Redis's <Set> score barrier for acquirers that should be removed from queue.
106
136
  #
107
137
  # @api private
108
138
  # @since 1.0.0
109
- def acquier_dead_score(queue_ttl)
139
+ def acquirer_dead_score(queue_ttl)
110
140
  Time.now.to_f - queue_ttl
111
141
  end
112
142
 
@@ -119,9 +149,9 @@ module RedisQueuedLocks::Resource
119
149
  Time.now.to_f - zombie_ttl
120
150
  end
121
151
 
122
- # @param acquier_position [Float]
152
+ # @param acquirer_position [Float]
123
153
  # A time (epoch, seconds.milliseconds) that represents
124
- # the acquier position in lock request queue.
154
+ # the acquirer position in lock request queue.
125
155
  # @parma queue_ttl [Integer]
126
156
  # In second.
127
157
  # @return [Boolean]
@@ -129,8 +159,8 @@ module RedisQueuedLocks::Resource
129
159
  #
130
160
  # @api private
131
161
  # @since 1.0.0
132
- def dead_score_reached?(acquier_position, queue_ttl)
133
- (acquier_position + queue_ttl) < Time.now.to_f
162
+ def dead_score_reached?(acquirer_position, queue_ttl)
163
+ (acquirer_position + queue_ttl) < Time.now.to_f
134
164
  end
135
165
 
136
166
  # @param lock_queue [String]
@@ -186,13 +216,20 @@ module RedisQueuedLocks::Resource
186
216
  # NOTE №2: we have no any approach to count Fiber objects in the current process without
187
217
  # object space API (or super memory-expensive) so host identification works without fibers;
188
218
  # NOTE №3: we still can extract thread objects via Thread.list API;
219
+
220
+ # @type var current_process_id: Integer
189
221
  current_process_id = get_process_id
222
+ # @type var current_threads: Array[Thread]
190
223
  current_threads = ::Thread.list
224
+ # @type var current_ractor_id: Integer
191
225
  current_ractor_id = get_ractor_id
192
226
 
193
- [].tap do |acquiers|
227
+ # NOTE: steep can't resolve a type of dynamic `[]` literal mutated via inline tap;
228
+ # steep:ignore:start
229
+ [].tap do |acquirers|
230
+ # @type var acquirers: Array[String]
194
231
  current_threads.each do |thread|
195
- acquiers << host_identifier(
232
+ acquirers << host_identifier(
196
233
  current_process_id,
197
234
  thread.object_id,
198
235
  current_ractor_id,
@@ -200,6 +237,7 @@ module RedisQueuedLocks::Resource
200
237
  )
201
238
  end
202
239
  end
240
+ # steep:ignore:end
203
241
  end
204
242
  end
205
243
  end
@@ -5,35 +5,36 @@
5
5
  module RedisQueuedLocks::Swarm::Acquirers
6
6
  class << self
7
7
  # Returns the list of swarm acquirers stored as HASH.
8
- # Format:
9
- # {
10
- # <acquirer id #1> => {
11
- # zombie: <Boolean>,
12
- # last_probe_time: <Time>,
13
- # last_probe_score: <Numeric>
14
- # },
15
- # <acquirer id #2> => {
16
- # zombie: <Boolean>,
17
- # last_probe_time: <Time>,
18
- # last_probe_score: <Numeric>
19
- # },
20
- # ...
21
- # }
22
8
  # Liveness probe time is represented as a float value (Time.now.to_f initially).
23
9
  #
24
10
  # @param redis_client [RedisClient]
25
11
  # @param zombie_ttl [Integer]
26
- # @return [Hash<String,Hash<Symbol,Float|Time>>]
12
+ # @return [Hash<String,Hash<Symbol,Float|Time>>] Format:
13
+ # {
14
+ # <acquirer id #1> => {
15
+ # zombie: <Boolean>,
16
+ # last_probe_time: <Time>,
17
+ # last_probe_score: <Numeric>
18
+ # },
19
+ # <acquirer id #2> => {
20
+ # zombie: <Boolean>,
21
+ # last_probe_time: <Time>,
22
+ # last_probe_score: <Numeric>
23
+ # },
24
+ # ...
25
+ # }
27
26
  #
28
27
  # @api private
29
28
  # @since 1.9.0
30
29
  def acquirers(redis_client, zombie_ttl)
31
30
  redis_client.with do |rconn|
32
31
  rconn.call('HGETALL', RedisQueuedLocks::Resource::SWARM_KEY).tap do |swarm_acqs|
32
+ # @type var swarm_acqs: Hash[String,untyped]
33
33
  swarm_acqs.transform_values! do |last_probe|
34
+ # @type var last_probe: String
34
35
  last_probe_score = last_probe.to_f
35
36
  last_probe_time = Time.at(last_probe_score)
36
- zombie_score = RedisQueuedLocks::Resource.calc_zombie_score(zombie_ttl / 1_000)
37
+ zombie_score = RedisQueuedLocks::Resource.calc_zombie_score(zombie_ttl / 1_000.0)
37
38
  is_zombie = last_probe_score < zombie_score
38
39
  { zombie: is_zombie, last_probe_time:, last_probe_score: }
39
40
  end
@@ -8,14 +8,13 @@ class RedisQueuedLocks::Swarm::FlushZombies < RedisQueuedLocks::Swarm::SwarmElem
8
8
  # @parma zombie_ttl [Integer]
9
9
  # @param lock_scan_size [Integer]
10
10
  # @param queue_scan_size [Integer]
11
- # @return [
12
- # RedisQueuedLocks::Data[
11
+ # @return [Hash<Symbol,Boolean|Set<String>]] Format:
12
+ # {
13
13
  # ok: <Boolean>,
14
14
  # deleted_zombie_hosts: <Set<String>>,
15
- # deleted_zombie_acquiers: <Set<String>>,
15
+ # deleted_zombie_acquirers: <Set<String>>,
16
16
  # deleted_zombie_locks: <Set<String>>
17
- # ]
18
- # ]
17
+ # }
19
18
  #
20
19
  # @api private
21
20
  # @since 1.9.0
@@ -30,7 +29,7 @@ class RedisQueuedLocks::Swarm::FlushZombies < RedisQueuedLocks::Swarm::SwarmElem
30
29
  # Step 1:
31
30
  # calculate zombie score (the time marker that shows acquirers that
32
31
  # have not announced live probes for a long time)
33
- zombie_score = RedisQueuedLocks::Resource.calc_zombie_score(zombie_ttl / 1_000)
32
+ zombie_score = RedisQueuedLocks::Resource.calc_zombie_score(zombie_ttl / 1_000.0)
34
33
 
35
34
  # Step 2: extract zombie acquirers from the swarm list
36
35
  zombie_hosts = rconn.call('HGETALL', RedisQueuedLocks::Resource::SWARM_KEY)
@@ -39,30 +38,32 @@ class RedisQueuedLocks::Swarm::FlushZombies < RedisQueuedLocks::Swarm::SwarmElem
39
38
  end
40
39
 
41
40
  # Step X: exit if we have no any zombie acquirer
42
- next RedisQueuedLocks::Data[
41
+ next {
43
42
  ok: true,
44
43
  deleted_zombie_hosts: Set.new,
45
44
  deleted_zombie_acquirers: Set.new,
46
- deleted_zombie_locks: Set.new,
47
- ] if zombie_hosts.empty?
45
+ deleted_zombie_locks: Set.new
46
+ } if zombie_hosts.empty?
48
47
 
49
48
  # Step 3: find zombie locks held by zombies and delete them
50
49
  # TODO: indexing (in order to prevent full database scan);
51
50
  # NOTE: original redis does not support indexing so we need to use
52
51
  # internal data structers to simulate data indexing (such as sorted sets or lists);
53
- zombie_locks = Set.new
54
- zombie_acquiers = Set.new
52
+ zombie_locks = Set.new #: Set[String]
53
+ zombie_acquirers = Set.new #: Set[String]
55
54
 
56
55
  rconn.scan(
57
56
  'MATCH', RedisQueuedLocks::Resource::LOCK_PATTERN, count: lock_scan_size
58
57
  ) do |lock_key|
59
- acquier_id, host_id = rconn.call('HMGET', lock_key, 'acq_id', 'hst_id')
58
+ acquirer_id, host_id = rconn.call('HMGET', lock_key, 'acq_id', 'hst_id')
60
59
  if zombie_hosts.include?(host_id)
61
60
  zombie_locks << lock_key
62
- zombie_acquiers << acquier_id
61
+ zombie_acquirers << acquirer_id
63
62
  end
64
63
  end
65
- rconn.call('DEL', *zombie_locks) if zombie_locks.any?
64
+
65
+ # NOTE: (steep) steep can't use <Set>s for splats
66
+ rconn.call('DEL', *zombie_locks) if zombie_locks.any? # steep:ignore
66
67
 
67
68
  # Step 4: find zombie requests => and drop them
68
69
  # TODO: indexing (in order to prevent full database scan);
@@ -71,8 +72,8 @@ class RedisQueuedLocks::Swarm::FlushZombies < RedisQueuedLocks::Swarm::SwarmElem
71
72
  rconn.scan(
72
73
  'MATCH', RedisQueuedLocks::Resource::LOCK_QUEUE_PATTERN, count: queue_scan_size
73
74
  ) do |lock_queue|
74
- zombie_acquiers.each do |zombie_acquier|
75
- rconn.call('ZREM', lock_queue, zombie_acquier)
75
+ zombie_acquirers.each do |zombie_acquirer|
76
+ rconn.call('ZREM', lock_queue, zombie_acquirer)
76
77
  end
77
78
  end
78
79
 
@@ -80,12 +81,12 @@ class RedisQueuedLocks::Swarm::FlushZombies < RedisQueuedLocks::Swarm::SwarmElem
80
81
  rconn.call('HDEL', RedisQueuedLocks::Resource::SWARM_KEY, *zombie_hosts)
81
82
 
82
83
  # Step 6: inform about deleted zombies
83
- RedisQueuedLocks::Data[
84
+ {
84
85
  ok: true,
85
86
  deleted_zombie_hosts: zombie_hosts,
86
- deleted_zombie_acquiers: zombie_acquiers,
87
+ deleted_zombie_acquirers: zombie_acquirers,
87
88
  deleted_zombie_locks: zombie_locks
88
- ]
89
+ }
89
90
  end
90
91
  end
91
92
  # rubocop:enable Metrics/MethodLength
@@ -96,7 +97,7 @@ class RedisQueuedLocks::Swarm::FlushZombies < RedisQueuedLocks::Swarm::SwarmElem
96
97
  # @api private
97
98
  # @since 1.9.0
98
99
  def enabled?
99
- rql_client.config[:swarm][:flush_zombies][:enabled_for_swarm]
100
+ rql_client.config['swarm.flush_zombies.enabled_for_swarm']
100
101
  end
101
102
 
102
103
  # @return [void]
@@ -105,11 +106,11 @@ class RedisQueuedLocks::Swarm::FlushZombies < RedisQueuedLocks::Swarm::SwarmElem
105
106
  # @since 1.9.0
106
107
  def swarm!
107
108
  @swarm_element = Ractor.new(
108
- rql_client.config.slice_value('swarm.flush_zombies.redis_config'),
109
- rql_client.config[:swarm][:flush_zombies][:zombie_ttl],
110
- rql_client.config[:swarm][:flush_zombies][:zombie_lock_scan_size],
111
- rql_client.config[:swarm][:flush_zombies][:zombie_queue_scan_size],
112
- rql_client.config[:swarm][:flush_zombies][:zombie_flush_period]
109
+ rql_client.config.slice('swarm.flush_zombies.redis_config'),
110
+ rql_client.config['swarm.flush_zombies.zombie_ttl'],
111
+ rql_client.config['swarm.flush_zombies.zombie_lock_scan_size'],
112
+ rql_client.config['swarm.flush_zombies.zombie_queue_scan_size'],
113
+ rql_client.config['swarm.flush_zombies.zombie_flush_period']
113
114
  ) do |rc, z_ttl, z_lss, z_qss, z_fl_prd|
114
115
  RedisQueuedLocks::Swarm::FlushZombies.swarm_loop do
115
116
  Thread.new do
@@ -4,24 +4,25 @@
4
4
  # @since 1.9.0
5
5
  class RedisQueuedLocks::Swarm::ProbeHosts < RedisQueuedLocks::Swarm::SwarmElement::Threaded
6
6
  class << self
7
+ # Returns a list of living hosts as a element command result. Result example:
8
+ # {
9
+ # ok: <Boolean>,
10
+ # result: {
11
+ # host_id1 <String> => score1 <String>,
12
+ # host_id2 <String> => score2 <String>,
13
+ # etc...
14
+ # }
15
+ # }
16
+ #
7
17
  # @param redis_client [RedisClient]
8
18
  # @param uniq_identity [String]
9
- # @return [
10
- # RedisQueuedLocks::Data[
11
- # ok: <Boolean>,
12
- # result: {
13
- # host_id1 <String> => score1 <String>,
14
- # host_id2 <String> => score2 <String>,
15
- # etc...
16
- # }
17
- # ]
18
- # ]
19
+ # @return [::Hash]
19
20
  #
20
21
  # @api private
21
22
  # @since 1.9.0
22
23
  def probe_hosts(redis_client, uniq_identity)
23
24
  possible_hosts = RedisQueuedLocks::Resource.possible_host_identifiers(uniq_identity)
24
- probed_hosts = {}
25
+ probed_hosts = {} #: Hash[String,Float]
25
26
 
26
27
  redis_client.with do |rconn|
27
28
  possible_hosts.each do |host_id|
@@ -33,9 +34,9 @@ class RedisQueuedLocks::Swarm::ProbeHosts < RedisQueuedLocks::Swarm::SwarmElemen
33
34
  )
34
35
  probed_hosts[host_id] = probe_score
35
36
  end
36
-
37
- RedisQueuedLocks::Data[ok: true, result: probed_hosts]
38
37
  end
38
+
39
+ { ok: true, result: probed_hosts }
39
40
  end
40
41
  end
41
42
 
@@ -44,7 +45,7 @@ class RedisQueuedLocks::Swarm::ProbeHosts < RedisQueuedLocks::Swarm::SwarmElemen
44
45
  # @api private
45
46
  # @since 1.9.0
46
47
  def enabled?
47
- rql_client.config[:swarm][:probe_hosts][:enabled_for_swarm]
48
+ rql_client.config['swarm.probe_hosts.enabled_for_swarm']
48
49
  end
49
50
 
50
51
  # @return [Thread]
@@ -54,15 +55,15 @@ class RedisQueuedLocks::Swarm::ProbeHosts < RedisQueuedLocks::Swarm::SwarmElemen
54
55
  def spawn_main_loop!
55
56
  Thread.new do
56
57
  redis_client = RedisQueuedLocks::Swarm::RedisClientBuilder.build(
57
- pooled: rql_client.config[:swarm][:probe_hosts][:redis_config][:pooled],
58
- sentinel: rql_client.config[:swarm][:probe_hosts][:redis_config][:sentinel],
59
- config: rql_client.config[:swarm][:probe_hosts][:redis_config][:config],
60
- pool_config: rql_client.config[:swarm][:probe_hosts][:redis_config][:pool_config]
58
+ pooled: rql_client.config['swarm.probe_hosts.redis_config.pooled'],
59
+ sentinel: rql_client.config['swarm.probe_hosts.redis_config.sentinel'],
60
+ config: rql_client.config['swarm.probe_hosts.redis_config.config'],
61
+ pool_config: rql_client.config['swarm.probe_hosts.redis_config.pool_config']
61
62
  )
62
63
 
63
64
  loop do
64
65
  RedisQueuedLocks::Swarm::ProbeHosts.probe_hosts(redis_client, rql_client.uniq_identity)
65
- sleep(rql_client.config[:swarm][:probe_hosts][:probe_period])
66
+ sleep(rql_client.config['swarm.probe_hosts.probe_period'])
66
67
  end
67
68
  end
68
69
  end
@@ -7,7 +7,7 @@ module RedisQueuedLocks::Swarm::RedisClientBuilder
7
7
  # @option pooled [Boolean]
8
8
  # @option sentinel [Boolean]
9
9
  # @option config [Hash]
10
- # @return [RedisClient]
10
+ # @return [RedisClient|RedisClient::Pooled]
11
11
  #
12
12
  # @api private
13
13
  # @since 1.9.0
@@ -28,7 +28,7 @@ module RedisQueuedLocks::Swarm::RedisClientBuilder
28
28
  private
29
29
 
30
30
  # @param config [Hash]
31
- # @return [RedisClient::Config]
31
+ # @return [RedisClient::SentinelConfig]
32
32
  #
33
33
  # @api private
34
34
  # @since 1.9.0
@@ -47,7 +47,7 @@ module RedisQueuedLocks::Swarm::RedisClientBuilder
47
47
 
48
48
  # @param redis_config [ReidsClient::Config]
49
49
  # @param pool_config [Hash]
50
- # @return [RedisClient]
50
+ # @return [RedisClient::Pooled]
51
51
  #
52
52
  # @api private
53
53
  # @since 1.9.0
@@ -43,11 +43,11 @@ class RedisQueuedLocks::Swarm::Supervisor
43
43
  @observable = observable
44
44
  @visor = Thread.new do
45
45
  loop do
46
- yield rescue nil # TODO/CHECK: may be we need to process exceptions here
47
- sleep(rql_client.config[:swarm][:supervisor][:liveness_probing_period])
46
+ yield rescue nil # TODO: (CHECK): may be we need to process exceptions here
47
+ sleep(rql_client.config['swarm.supervisor.liveness_probing_period'])
48
48
  end
49
49
  end
50
- # NOTE: need to give a timespot to initialize visor thread;
50
+ # NOTE: need to give a timespot to initialize a visor thread;
51
51
  sleep(0.1)
52
52
  end
53
53
 
@@ -56,7 +56,11 @@ class RedisQueuedLocks::Swarm::Supervisor
56
56
  # @api private
57
57
  # @since 1.9.0
58
58
  def running?
59
- visor != nil && visor.alive?
59
+ # NOTE:
60
+ # steep can not understand that visor.alive? is invoked on
61
+ # `::Thread` here (not on `::Thread | nil` after the `nil`-check);
62
+ # so we need to ignore this check temporary and wait the best future :)
63
+ visor != nil && visor.alive? # steep:ignore
60
64
  end
61
65
 
62
66
  # @return [void]
@@ -64,7 +68,11 @@ class RedisQueuedLocks::Swarm::Supervisor
64
68
  # @api private
65
69
  # @since 1.9.0
66
70
  def stop!
67
- visor.kill if running?
71
+ # NOTE:
72
+ # steep can not understand that visor.kill is invoked on
73
+ # `::Thread` here (not on `::Thread | nil` after the `nil`-check);
74
+ # so we need to ignore this check temporary and wait the best future :)
75
+ visor.kill if running? # steep:ignore
68
76
  @visor = nil
69
77
  @observable = nil
70
78
  end
@@ -74,9 +82,14 @@ class RedisQueuedLocks::Swarm::Supervisor
74
82
  # @api private
75
83
  # @since 1.9.0
76
84
  def status
85
+ # NOTE:
86
+ # steep can not understand that thread_state(visor) is invoked on
87
+ # `::Thread` here (not on `::Thread | nil` after the `nil`-check);
88
+ # so we need to ignore this check temporary and wait the best future :)
89
+
77
90
  {
78
91
  running: running?,
79
- state: (visor == nil) ? 'non_initialized' : thread_state(visor),
92
+ state: (visor == nil) ? 'non_initialized' : thread_state(visor), # steep:ignore
80
93
  observable: (observable == nil) ? 'non_initialized' : 'initialized'
81
94
  }
82
95
  end
@@ -25,6 +25,7 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated
25
25
  # @since 1.9.0
26
26
  attr_reader :sync
27
27
 
28
+ # @param rql_client [RedisQueuedLocks::Client]
28
29
  # @return [void]
29
30
  #
30
31
  # @api private
@@ -80,12 +81,12 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated
80
81
  #
81
82
  # @api private
82
83
  # @since 1.9.0
83
- def enabled?
84
+ def enabled? # steep:ignore
84
85
  # NOTE: provide an <is enabled> logic here by analyzing the redis queued locks config.
85
86
  end
86
87
 
87
- # @return [Hash<Symbol,Boolean|Hash<Symbol,String|Boolean>>]
88
- # Format: {
88
+ # @return [Hash<Symbol,Boolean|Hash<Symbol,String|Boolean>>] Format:
89
+ # {
89
90
  # enabled: <Boolean>,
90
91
  # ractor: {
91
92
  # running: <Boolean>,
@@ -102,16 +103,16 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated
102
103
  def status
103
104
  sync.synchronize do
104
105
  ractor_running = swarmed__alive?
105
- ractor_state = swarmed? ? ractor_status(swarm_element) : 'non_initialized'
106
+ ractor_state = swarmed? ? ractor_status(swarm_element) : 'non_initialized' # steep:ignore
106
107
 
107
- main_loop_running = nil
108
- main_loop_state = nil
109
108
  begin
110
109
  main_loop_running = swarmed__running?
110
+ # steep:ignore:start
111
111
  main_loop_state =
112
112
  main_loop_running ? swarm_loop__status[:main_loop][:state] : 'non_initialized'
113
+ # steep:ignore:end
113
114
  rescue Ractor::ClosedError
114
- # NOTE: it can happend when you run RedisQueuedLocks::Swarm#deswarm!;
115
+ # NOTE: it can happend when you running RedisQueuedLocks::Swarm#deswarm!
115
116
  main_loop_running = false
116
117
  main_loop_state = 'non_initialized'
117
118
  end
@@ -160,6 +161,7 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated
160
161
  # to provide better code readability (it is placed next to the method inside
161
162
  # wich it should be called (see #swarm!)). That's why some rubocop cops are disabled.
162
163
 
164
+ # @type var main_loop: Thread?
163
165
  main_loop = nil
164
166
 
165
167
  loop do
@@ -167,24 +169,24 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated
167
169
 
168
170
  case command
169
171
  when :status
170
- main_loop_alive = main_loop != nil && main_loop.alive?
172
+ main_loop_alive = main_loop != nil && main_loop.alive? # steep:ignore
171
173
  main_loop_state =
172
174
  if main_loop == nil
173
175
  'non_initialized'
174
176
  else
175
- # NOTE: (full name resolution): ractor has no syntax-based constatnt context;
177
+ # @type var main_loop: Thread
176
178
  RedisQueuedLocks::Utilities.thread_state(main_loop)
177
179
  end
178
180
  Ractor.yield({ main_loop: { alive: main_loop_alive, state: main_loop_state } })
179
181
  when :is_active
180
- Ractor.yield(main_loop != nil && main_loop.alive?)
182
+ Ractor.yield(main_loop != nil && main_loop.alive?) # steep:ignore
181
183
  when :start
182
- main_loop.kill if main_loop != nil
184
+ main_loop.kill if main_loop != nil # steep:ignore
183
185
  main_loop = yield # REFERENCE: `main_loop_spawner.call`
184
186
  when :stop
185
- main_loop.kill if main_loop != nil
187
+ main_loop.kill if main_loop != nil # steep:ignore
186
188
  when :kill
187
- main_loop.kill if main_loop != nil
189
+ main_loop.kill if main_loop != nil # steep:ignore
188
190
  exit
189
191
  end
190
192
  end
@@ -212,7 +214,7 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated
212
214
  # @api private
213
215
  # @since 1.9.0
214
216
  def swarmed__alive?
215
- swarm_element != nil && ractor_alive?(swarm_element)
217
+ swarm_element != nil && ractor_alive?(swarm_element) # steep:ignore
216
218
  end
217
219
 
218
220
  # @return [Boolean]
@@ -220,7 +222,7 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated
220
222
  # @api private
221
223
  # @since 1.9.0
222
224
  def swarmed__dead?
223
- swarm_element != nil && !ractor_alive?(swarm_element)
225
+ swarm_element != nil && !ractor_alive?(swarm_element) # steep:ignore
224
226
  end
225
227
 
226
228
  # @return [Boolean]
@@ -228,7 +230,7 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated
228
230
  # @api private
229
231
  # @since 1.9.0
230
232
  def swarmed__running?
231
- swarm_element != nil && ractor_alive?(swarm_element) && swarm_loop__is_active
233
+ swarm_element != nil && ractor_alive?(swarm_element) && swarm_loop__is_active # steep:ignore
232
234
  end
233
235
 
234
236
  # @return [Boolean]
@@ -236,7 +238,7 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated
236
238
  # @api private
237
239
  # @since 1.9.0
238
240
  def swarmed__stopped?
239
- swarm_element != nil && ractor_alive?(swarm_element) && !swarm_loop__is_active
241
+ swarm_element != nil && ractor_alive?(swarm_element) && !swarm_loop__is_active # steep:ignore
240
242
  end
241
243
 
242
244
  # @return [Boolean]
@@ -244,7 +246,7 @@ class RedisQueuedLocks::Swarm::SwarmElement::Isolated
244
246
  # @api private
245
247
  # @since 1.9.0
246
248
  def swarm_loop__is_active
247
- return if idle? || swarmed__dead?
249
+ return false if idle? || swarmed__dead?
248
250
  sync.synchronize { swarm_element.send(:is_active).take }
249
251
  end
250
252