redis_queued_locks 1.7.0 → 1.9.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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/CHANGELOG.md +60 -1
  4. data/README.md +485 -46
  5. data/lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +4 -0
  6. data/lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue.rb +4 -1
  7. data/lib/redis_queued_locks/acquier/acquire_lock/instr_visitor.rb +20 -5
  8. data/lib/redis_queued_locks/acquier/acquire_lock/log_visitor.rb +24 -0
  9. data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock/log_visitor.rb +56 -0
  10. data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock.rb +37 -30
  11. data/lib/redis_queued_locks/acquier/acquire_lock/with_acq_timeout.rb +41 -7
  12. data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire/log_visitor.rb +8 -0
  13. data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire.rb +21 -9
  14. data/lib/redis_queued_locks/acquier/acquire_lock.rb +61 -22
  15. data/lib/redis_queued_locks/acquier/clear_dead_requests.rb +5 -1
  16. data/lib/redis_queued_locks/acquier/extend_lock_ttl.rb +5 -1
  17. data/lib/redis_queued_locks/acquier/lock_info.rb +4 -3
  18. data/lib/redis_queued_locks/acquier/locks.rb +2 -2
  19. data/lib/redis_queued_locks/acquier/queue_info.rb +2 -2
  20. data/lib/redis_queued_locks/acquier/release_all_locks.rb +12 -2
  21. data/lib/redis_queued_locks/acquier/release_lock.rb +12 -2
  22. data/lib/redis_queued_locks/client.rb +320 -10
  23. data/lib/redis_queued_locks/errors.rb +8 -0
  24. data/lib/redis_queued_locks/instrument.rb +8 -1
  25. data/lib/redis_queued_locks/logging.rb +8 -1
  26. data/lib/redis_queued_locks/resource.rb +59 -1
  27. data/lib/redis_queued_locks/swarm/acquirers.rb +44 -0
  28. data/lib/redis_queued_locks/swarm/flush_zombies.rb +133 -0
  29. data/lib/redis_queued_locks/swarm/probe_hosts.rb +69 -0
  30. data/lib/redis_queued_locks/swarm/redis_client_builder.rb +67 -0
  31. data/lib/redis_queued_locks/swarm/supervisor.rb +83 -0
  32. data/lib/redis_queued_locks/swarm/swarm_element/isolated.rb +287 -0
  33. data/lib/redis_queued_locks/swarm/swarm_element/threaded.rb +351 -0
  34. data/lib/redis_queued_locks/swarm/swarm_element.rb +8 -0
  35. data/lib/redis_queued_locks/swarm/zombie_info.rb +145 -0
  36. data/lib/redis_queued_locks/swarm.rb +241 -0
  37. data/lib/redis_queued_locks/utilities/lock.rb +22 -0
  38. data/lib/redis_queued_locks/utilities.rb +75 -0
  39. data/lib/redis_queued_locks/version.rb +2 -2
  40. data/lib/redis_queued_locks.rb +2 -0
  41. data/redis_queued_locks.gemspec +6 -10
  42. metadata +24 -6
  43. data/lib/redis_queued_locks/watcher.rb +0 -1
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 1.9.0
5
+ module RedisQueuedLocks::Swarm::ZombieInfo
6
+ class << self
7
+ # @param redis_client [RedisClient]
8
+ # @param zombie_ttl [Integer]
9
+ # @param lock_scan_size [Integer]
10
+ # @return [Hash<Symbol,Set<String>>]
11
+ # Format: {
12
+ # zombie_hosts: <Set<String>>,
13
+ # zombie_acquirers: <Set<String>>,
14
+ # zombie_locks: <Set<String>>
15
+ # }
16
+ #
17
+ # @api private
18
+ # @since 1.9.0
19
+ def zombies_info(redis_client, zombie_ttl, lock_scan_size)
20
+ redis_client.with do |rconn|
21
+ extract_all(rconn, zombie_ttl, lock_scan_size)
22
+ end
23
+ end
24
+
25
+ # @param redis_client [RedisClient]
26
+ # @param zombie_ttl [Integer]
27
+ # @param lock_scan_size [Integer]
28
+ # @return [Set<String>]
29
+ #
30
+ # @api private
31
+ # @since 1.9.0
32
+ def zombie_locks(redis_client, zombie_ttl, lock_scan_size)
33
+ redis_client.with do |rconn|
34
+ extract_zombie_locks(rconn, zombie_ttl, lock_scan_size)
35
+ end
36
+ end
37
+
38
+ # @param redis_client [RedisClient]
39
+ # @param zombie_ttl [Integer]
40
+ # @return [Set<String>]
41
+ #
42
+ # @api private
43
+ # @since 1.9.0
44
+ def zombie_hosts(redis_client, zombie_ttl)
45
+ redis_client.with do |rconn|
46
+ extract_zombie_hosts(rconn, zombie_ttl)
47
+ end
48
+ end
49
+
50
+ # @param redis_client [RedisClient]
51
+ # @param zombie_ttl [Integer]
52
+ # @param lock_scan_size [Integer]
53
+ # @return [Set<String>]
54
+ #
55
+ # @api private
56
+ # @since 1.9.0
57
+ def zombie_acquiers(redis_client, zombie_ttl, lock_scan_size)
58
+ redis_client.with do |rconn|
59
+ extract_zombie_acquiers(rconn, zombie_ttl, lock_scan_size)
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ # @param rconn [RedisClient] redis connection obtained via `#with` from RedisClient instance;
66
+ # @param zombie_ttl [Integer]
67
+ # @return [Set<String>]
68
+ #
69
+ # @api private
70
+ # @since 1.9.0
71
+ def extract_zombie_hosts(rconn, zombie_ttl)
72
+ zombie_score = RedisQueuedLocks::Resource.calc_zombie_score(zombie_ttl / 1_000)
73
+ swarmed_hosts = rconn.call('HGETALL', RedisQueuedLocks::Resource::SWARM_KEY)
74
+ swarmed_hosts.each_with_object(Set.new) do |(hst_id, ts), zombies|
75
+ (zombies << hst_id) if (zombie_score > ts.to_f)
76
+ end
77
+ end
78
+
79
+ # @param rconn [RedisClient] redis connection obtained via `#with` from RedisClient instance;
80
+ # @param zombie_ttl [Integer]
81
+ # @param lock_scan_size [Integer]
82
+ # @return [Set<String>]
83
+ #
84
+ # @api private
85
+ # @since 1.9.0
86
+ def extract_zombie_locks(rconn, zombie_ttl, lock_scan_size)
87
+ zombie_hosts = extract_zombie_hosts(rconn, zombie_ttl)
88
+ zombie_locks = Set.new
89
+ rconn.scan(
90
+ 'MATCH', RedisQueuedLocks::Resource::LOCK_PATTERN, count: lock_scan_size
91
+ ) do |lock_key|
92
+ _acquier_id, host_id = rconn.call('HMGET', lock_key, 'acq_id', 'hst_id')
93
+ zombie_locks << lock_key if zombie_hosts.include?(host_id)
94
+ end
95
+ zombie_locks
96
+ end
97
+
98
+ # @param rconn [RedisClient] redis connection obtained via `#with` from RedisClient instance;
99
+ # @param zombie_ttl [Integer]
100
+ # @param lock_scan_size [Integer]
101
+ # @return [Set<String>]
102
+ #
103
+ # @api private
104
+ # @since 1.9.0
105
+ def extract_zombie_acquiers(rconn, zombie_ttl, lock_scan_size)
106
+ zombie_hosts = extract_zombie_hosts(rconn, zombie_ttl)
107
+ zombie_acquirers = Set.new
108
+ rconn.scan(
109
+ 'MATCH', RedisQueuedLocks::Resource::LOCK_PATTERN, count: lock_scan_size
110
+ ) do |lock_key|
111
+ acquier_id, host_id = rconn.call('HMGET', lock_key, 'acq_id', 'hst_id')
112
+ zombie_acquirers << acquier_id if zombie_hosts.include?(host_id)
113
+ end
114
+ zombie_acquirers
115
+ end
116
+
117
+ # @param rconn [RedisClient] redis connection obtained via `#with` from RedisClient instance;
118
+ # @param zombie_ttl [Integer]
119
+ # @param lock_scan_size [Integer]
120
+ # @return [Hash<Symbol,<Set<String>>]
121
+ # Format: {
122
+ # zombie_hosts: <Set<String>>,
123
+ # zombie_acquirers: <Set<String>>,
124
+ # zombie_locks: <Set<String>>
125
+ # }
126
+ #
127
+ # @api private
128
+ # @since 1.9.0
129
+ def extract_all(rconn, zombie_ttl, lock_scan_size)
130
+ zombie_hosts = extract_zombie_hosts(rconn, zombie_ttl)
131
+ zombie_locks = Set.new
132
+ zombie_acquirers = Set.new
133
+ rconn.scan(
134
+ 'MATCH', RedisQueuedLocks::Resource::LOCK_PATTERN, count: lock_scan_size
135
+ ) do |lock_key|
136
+ acquier_id, host_id = rconn.call('HMGET', lock_key, 'acq_id', 'hst_id')
137
+ if zombie_hosts.include?(host_id)
138
+ zombie_acquirers << acquier_id
139
+ zombie_locks << lock_key
140
+ end
141
+ end
142
+ { zombie_hosts:, zombie_acquirers:, zombie_locks: }
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,241 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 1.9.0
5
+ # rubocop:disable Metrics/ClassLength
6
+ class RedisQueuedLocks::Swarm
7
+ require_relative 'swarm/redis_client_builder'
8
+ require_relative 'swarm/supervisor'
9
+ require_relative 'swarm/acquirers'
10
+ require_relative 'swarm/zombie_info'
11
+ require_relative 'swarm/swarm_element'
12
+ require_relative 'swarm/probe_hosts'
13
+ require_relative 'swarm/flush_zombies'
14
+
15
+ # @return [RedisQueuedLocks::Client]
16
+ #
17
+ # @api private
18
+ # @since 1.9.0
19
+ attr_reader :rql_client
20
+
21
+ # @return [RedisQueuedLocks::Swarm::Supervisor]
22
+ #
23
+ # @api private
24
+ # @since 1.9.0
25
+ attr_reader :supervisor
26
+
27
+ # @return [RedisQueuedLocks::Swarm::ProbeHosts]
28
+ #
29
+ # @api private
30
+ # @since 1.9.0
31
+ attr_reader :probe_hosts_element
32
+
33
+ # @return [RedisQueuedLocks::Swarm::FlushZombies]
34
+ #
35
+ # @api private
36
+ # @since 1.9.0
37
+ attr_reader :flush_zombies_element
38
+
39
+ # @return [RedisQueuedLocks::Utilities::Lock]
40
+ #
41
+ # @api private
42
+ # @since 1.9.0
43
+ attr_reader :sync
44
+
45
+ # @param rql_client [RedisQueuedLocks::Client]
46
+ # @return [void]
47
+ #
48
+ # @api private
49
+ # @since 1.9.0
50
+ def initialize(rql_client)
51
+ @rql_client = rql_client
52
+ @sync = RedisQueuedLocks::Utilities::Lock.new
53
+ @supervisor = RedisQueuedLocks::Swarm::Supervisor.new(rql_client)
54
+ @probe_hosts_element = RedisQueuedLocks::Swarm::ProbeHosts.new(rql_client)
55
+ @flush_zombies_element = RedisQueuedLocks::Swarm::FlushZombies.new(rql_client)
56
+ end
57
+
58
+ # @return [Hash<Symbol,Boolean|<Hash<Symbol,Boolean>>]
59
+ #
60
+ # @api public
61
+ # @since 1.9.0
62
+ def swarm_status
63
+ sync.synchronize do
64
+ {
65
+ auto_swarm: rql_client.config[:swarm][:auto_swarm],
66
+ supervisor: supervisor.status,
67
+ probe_hosts: probe_hosts_element.status,
68
+ flush_zombies: flush_zombies_element.status
69
+ }
70
+ end
71
+ end
72
+ alias_method :swarm_state, :swarm_status
73
+
74
+ # @option zombie_ttl [Integer]
75
+ # @return [Hash<String,Hash<Symbol,Float|Time>>]
76
+ #
77
+ # @api public
78
+ # @since 1.9.0
79
+ def swarm_info(zombie_ttl: rql_client.config[:swarm][:flush_zombies][:zombie_ttl])
80
+ RedisQueuedLocks::Swarm::Acquirers.acquirers(
81
+ rql_client.redis_client,
82
+ zombie_ttl
83
+ )
84
+ end
85
+
86
+ # @return [
87
+ # RedisQueuedLocks::Data[
88
+ # ok: <Boolean>,
89
+ # result: {
90
+ # host_id1 <String> => score1 <String>,
91
+ # host_id2 <String> => score2 <String>,
92
+ # etc...
93
+ # }
94
+ # ]
95
+ # ]
96
+ #
97
+ # @api public
98
+ # @since 1.9.0
99
+ def probe_hosts
100
+ RedisQueuedLocks::Swarm::ProbeHosts.probe_hosts(
101
+ rql_client.redis_client,
102
+ rql_client.uniq_identity
103
+ )
104
+ end
105
+
106
+ # @option zombie_ttl [Integer]
107
+ # @option lock_scan_size [Integer]
108
+ # @option queue_scan_size [Integer]
109
+ # @return [
110
+ # RedisQueuedLocks::Data[
111
+ # ok: <Boolean>,
112
+ # deleted_zombie_hosts: <Set<String>>,
113
+ # deleted_zombie_acquiers: <Set<String>>,
114
+ # deleted_zombie_locks: <Set<String>>
115
+ # ]
116
+ # ]
117
+ #
118
+ # @api public
119
+ # @since 1.9.0
120
+ def flush_zombies(
121
+ zombie_ttl: rql_client.config[:swarm][:flush_zombies][:zombie_ttl],
122
+ lock_scan_size: rql_client.config[:swarm][:flush_zombies][:zombie_lock_scan_size],
123
+ queue_scan_size: rql_client.config[:swarm][:flush_zombies][:zombie_queue_scan_size]
124
+ )
125
+ RedisQueuedLocks::Swarm::FlushZombies.flush_zombies(
126
+ rql_client.redis_client,
127
+ zombie_ttl,
128
+ lock_scan_size,
129
+ queue_scan_size
130
+ )
131
+ end
132
+
133
+ # @return [Set<String>]
134
+ #
135
+ # @api public
136
+ # @since 1.9.0
137
+ def zombie_locks(
138
+ zombie_ttl: rql_client.config[:swarm][:flush_zombies][:zombie_ttl],
139
+ lock_scan_size: rql_client.config[:swarm][:flush_zombies][:zombie_lock_scan_size]
140
+ )
141
+ RedisQueuedLocks::Swarm::ZombieInfo.zombie_locks(
142
+ rql_client.redis_client,
143
+ zombie_ttl,
144
+ lock_scan_size
145
+ )
146
+ end
147
+
148
+ # @return [Set<String>]
149
+ #
150
+ # @api ppublic
151
+ # @since 1.9.0
152
+ def zombie_acquiers(
153
+ zombie_ttl: rql_client.config[:swarm][:flush_zombies][:zombie_ttl],
154
+ lock_scan_size: rql_client.config[:swarm][:flush_zombies][:zombie_lock_scan_size]
155
+ )
156
+ RedisQueuedLocks::Swarm::ZombieInfo.zombie_acquiers(
157
+ rql_client.redis_client,
158
+ zombie_ttl,
159
+ lock_scan_size
160
+ )
161
+ end
162
+
163
+ # @return [Set<String>]
164
+ #
165
+ # @api public
166
+ # @since 1.9.0
167
+ def zombie_hosts(zombie_ttl: rql_client.config[:swarm][:flush_zombies][:zombie_ttl])
168
+ RedisQueuedLocks::Swarm::ZombieInfo.zombie_hosts(rql_client.redis_client, zombie_ttl)
169
+ end
170
+
171
+ # @return [Hash<Symbol,Set<String>>]
172
+ # Format: {
173
+ # zombie_hosts: <Set<String>>,
174
+ # zombie_acquirers: <Set<String>>,
175
+ # zombie_locks: <Set<String>>
176
+ # }
177
+ #
178
+ # @api public
179
+ # @since 1.9.0
180
+ def zombies_info(
181
+ zombie_ttl: rql_client.config[:swarm][:flush_zombies][:zombie_ttl],
182
+ lock_scan_size: rql_client.config[:swarm][:flush_zombies][:zombie_lock_scan_size]
183
+ )
184
+ RedisQueuedLocks::Swarm::ZombieInfo.zombies_info(
185
+ rql_client.redis_client,
186
+ zombie_ttl,
187
+ lock_scan_size
188
+ )
189
+ end
190
+
191
+ # @option silently [Boolean]
192
+ # @return [NilClass,Hash<Symbol,Symbol|Boolean>]
193
+ #
194
+ # @api public
195
+ # @since 1.9.0
196
+ def swarm!
197
+ sync.synchronize do
198
+ # Step 0:
199
+ # - stop the supervisor (kill internal observer objects if supervisor is alredy running);
200
+ supervisor.stop!
201
+
202
+ # Step 1:
203
+ # - initialize swarm elements and start their main loops;
204
+ probe_hosts_element.try_swarm!
205
+ flush_zombies_element.try_swarm!
206
+
207
+ # Step 2:
208
+ # - run supervisor that should keep running created swarm elements and their main loops;
209
+ unless supervisor.running?
210
+ supervisor.observe! do
211
+ probe_hosts_element.reswarm_if_dead!
212
+ flush_zombies_element.reswarm_if_dead!
213
+ end
214
+ end
215
+
216
+ # NOTE: need to give a little timespot to initialize ractor objects and their main loops;
217
+ sleep(0.1)
218
+
219
+ RedisQueuedLocks::Data[ok: true, result: :swarming]
220
+ end
221
+ end
222
+
223
+ # @option silently [Boolean]
224
+ # @return [NilClass,Hash<Symbol,Symbol|Boolean>]
225
+ #
226
+ # @api public
227
+ # @since 1.9.0
228
+ def deswarm!
229
+ sync.synchronize do
230
+ supervisor.stop!
231
+ probe_hosts_element.try_kill!
232
+ flush_zombies_element.try_kill!
233
+
234
+ # NOTE: need to give a little timespot to stop ractor objects and their main loops;
235
+ sleep(0.1)
236
+
237
+ RedisQueuedLocks::Data[ok: true, result: :terminating]
238
+ end
239
+ end
240
+ end
241
+ # rubocop:enable Metrics/ClassLength
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 1.9.0
5
+ class RedisQueuedLocks::Utilities::Lock
6
+ # @return [void]
7
+ #
8
+ # @api private
9
+ # @since 1.9.0
10
+ def initialize
11
+ @lock = ::Mutex.new
12
+ end
13
+
14
+ # @param block [Block]
15
+ # @return [Any]
16
+ #
17
+ # @api private
18
+ # @since 1.9.0
19
+ def synchronize(&block)
20
+ @lock.owned? ? yield : @lock.synchronize(&block)
21
+ end
22
+ end
@@ -3,8 +3,38 @@
3
3
  # @api private
4
4
  # @since 1.0.0
5
5
  module RedisQueuedLocks::Utilities
6
+ require_relative 'utilities/lock'
7
+
6
8
  module_function
7
9
 
10
+ # Ractor class has no methods for Ractor object status identification.
11
+ # The only one approach (without C/FFI extending) to give the status is to check
12
+ # the status from the `#inspect/#to_s` methods. String representation has the following format:
13
+ # Format: "#<Ractor:##{id}#{name ? ' '+name : ''}#{loc ? " " + loc : ''} #{status}>"
14
+ # Example: #<Ractor:#2 (irb):2 terminated>
15
+ # So we need to parse the `status` part of the inspect method and use it for our logic.
16
+ # Current regexp object provides the pattern for this.
17
+ #
18
+ # @return [Regexp]
19
+ #
20
+ # @api private
21
+ # @since 1.9.0
22
+ RACTOR_LIVENESS_PATTERN = /\A.*?(created|running|blocking).*?\z/i
23
+
24
+ # Ractor status as a string extracted from the object string representation.
25
+ # This way is used cuz the ractor class has no any detailed status extraction API.
26
+ # Possible statuses (at the moment of Ruby@3.4):
27
+ # - "created"
28
+ # - "blocking"
29
+ # - "running"
30
+ # - "terminated"
31
+ #
32
+ # @return [Regexp]
33
+ #
34
+ # @api private
35
+ # @since 1.9.0
36
+ RACTOR_STATUS_PATTERN = /\A.*?\s(?<status>\w+)>\z/i
37
+
8
38
  # @param block [Block]
9
39
  # @return [Any]
10
40
  #
@@ -13,4 +43,49 @@ module RedisQueuedLocks::Utilities
13
43
  def run_non_critical(&block)
14
44
  yield rescue nil
15
45
  end
46
+
47
+ # Possible statuses (at the moment of Ruby@3.4):
48
+ # - "created"
49
+ # - "blocking"
50
+ # - "running"
51
+ # - "terminated"
52
+ #
53
+ # @param ractor [Ractor]
54
+ # @return [String]
55
+ #
56
+ # @api private
57
+ # @since 1.9.0
58
+ def ractor_status(ractor)
59
+ ractor.to_s.match(RACTOR_STATUS_PATTERN)[:status]
60
+ end
61
+
62
+ # @param ractor [Ractor]
63
+ # @return [Boolean]
64
+ #
65
+ # @api private
66
+ # @since 1.9.0
67
+ def ractor_alive?(ractor)
68
+ ractor.to_s.match?(RACTOR_LIVENESS_PATTERN)
69
+ end
70
+
71
+ # Returns the status of the passed thread object.
72
+ # Possible statuses:
73
+ # - "run" (thread is executing);
74
+ # - "sleep" (thread is sleeping or waiting on I/O);
75
+ # - "aborting" (thread is aborting)
76
+ # - "dead" (thread is terminated normally);
77
+ # - "failed" (thread is terminated with an exception);
78
+ # See Thread#status official documentation.
79
+ #
80
+ # @param [Thread]
81
+ # @return [String]
82
+ #
83
+ # @api private
84
+ # @since 1.9.0
85
+ def thread_state(thread)
86
+ status = thread.status
87
+ return 'dead' if status == false
88
+ return 'failed' if status == nil
89
+ status
90
+ end
16
91
  end
@@ -5,6 +5,6 @@ module RedisQueuedLocks
5
5
  #
6
6
  # @api public
7
7
  # @since 0.0.1
8
- # @version 1.7.0
9
- VERSION = '1.7.0'
8
+ # @version 1.9.0
9
+ VERSION = '1.9.0'
10
10
  end
@@ -5,6 +5,7 @@ require 'qonfig'
5
5
  require 'timeout'
6
6
  require 'securerandom'
7
7
  require 'logger'
8
+ require 'objspace'
8
9
 
9
10
  # @api public
10
11
  # @since 1.0.0
@@ -18,6 +19,7 @@ module RedisQueuedLocks
18
19
  require_relative 'redis_queued_locks/resource'
19
20
  require_relative 'redis_queued_locks/acquier'
20
21
  require_relative 'redis_queued_locks/instrument'
22
+ require_relative 'redis_queued_locks/swarm'
21
23
  require_relative 'redis_queued_locks/client'
22
24
 
23
25
  # @since 1.0.0
@@ -15,21 +15,17 @@ Gem::Specification.new do |spec|
15
15
  'capabilities based on the Redis Database.'
16
16
 
17
17
  spec.description =
18
- 'Distributed locks with "prioritized lock acquisition queue" capabilities ' \
18
+ '|> Distributed locks with "prioritized lock acquisition queue" capabilities ' \
19
19
  'based on the Redis Database. ' \
20
- # ---
21
- 'Each lock request is put into the request queue ' \
22
- "(each lock is hosted by it's own queue separately from other queues) and processed " \
20
+ '|> Each lock request is put into the request queue ' \
21
+ '(each lock is hosted by it\'s own queue separately from other queues) and processed ' \
23
22
  'in order of their priority (FIFO). ' \
24
- # ---
25
- 'Each lock request lives some period of time (RTTL) ' \
23
+ '|> Each lock request lives some period of time (RTTL) ' \
26
24
  '(with requeue capabilities) which guarantees the request queue will never be stacked. ' \
27
- # ---
28
- 'In addition to the classic `queued` (FIFO) strategy RQL supports ' \
25
+ '|> In addition to the classic `queued` (FIFO) strategy RQL supports ' \
29
26
  '`random` (RANDOM) lock obtaining strategy when any acquirer from the lock queue ' \
30
27
  'can obtain the lock regardless the position in the queue. ' \
31
- # ---
32
- 'Provides flexible invocation flow, parametrized limits ' \
28
+ '|> Provides flexible invocation flow, parametrized limits ' \
33
29
  '(lock request ttl, lock ttl, queue ttl, lock attempts limit, fast failing, etc), ' \
34
30
  'logging and instrumentation.'
35
31
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis_queued_locks
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rustam Ibragimov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-12 00:00:00.000000000 Z
11
+ date: 2024-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis-client
@@ -38,8 +38,16 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.28'
41
- description: 'Distributed locks with "prioritized lock acquisition queue" capabilities
42
- based on the Redis Database. '
41
+ description: '|> Distributed locks with "prioritized lock acquisition queue" capabilities
42
+ based on the Redis Database. |> Each lock request is put into the request queue
43
+ (each lock is hosted by it''s own queue separately from other queues) and processed
44
+ in order of their priority (FIFO). |> Each lock request lives some period of time
45
+ (RTTL) (with requeue capabilities) which guarantees the request queue will never
46
+ be stacked. |> In addition to the classic `queued` (FIFO) strategy RQL supports
47
+ `random` (RANDOM) lock obtaining strategy when any acquirer from the lock queue
48
+ can obtain the lock regardless the position in the queue. |> Provides flexible invocation
49
+ flow, parametrized limits (lock request ttl, lock ttl, queue ttl, lock attempts
50
+ limit, fast failing, etc), logging and instrumentation.'
43
51
  email:
44
52
  - iamdaiver@gmail.com
45
53
  executables: []
@@ -91,9 +99,19 @@ files:
91
99
  - lib/redis_queued_locks/logging/sampler.rb
92
100
  - lib/redis_queued_locks/logging/void_logger.rb
93
101
  - lib/redis_queued_locks/resource.rb
102
+ - lib/redis_queued_locks/swarm.rb
103
+ - lib/redis_queued_locks/swarm/acquirers.rb
104
+ - lib/redis_queued_locks/swarm/flush_zombies.rb
105
+ - lib/redis_queued_locks/swarm/probe_hosts.rb
106
+ - lib/redis_queued_locks/swarm/redis_client_builder.rb
107
+ - lib/redis_queued_locks/swarm/supervisor.rb
108
+ - lib/redis_queued_locks/swarm/swarm_element.rb
109
+ - lib/redis_queued_locks/swarm/swarm_element/isolated.rb
110
+ - lib/redis_queued_locks/swarm/swarm_element/threaded.rb
111
+ - lib/redis_queued_locks/swarm/zombie_info.rb
94
112
  - lib/redis_queued_locks/utilities.rb
113
+ - lib/redis_queued_locks/utilities/lock.rb
95
114
  - lib/redis_queued_locks/version.rb
96
- - lib/redis_queued_locks/watcher.rb
97
115
  - redis_queued_locks.gemspec
98
116
  homepage: https://github.com/0exp/redis_queued_locks
99
117
  licenses:
@@ -117,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
135
  - !ruby/object:Gem::Version
118
136
  version: '0'
119
137
  requirements: []
120
- rubygems_version: 3.3.7
138
+ rubygems_version: 3.5.11
121
139
  signing_key:
122
140
  specification_version: 4
123
141
  summary: Distributed locks with "prioritized lock acquisition queue" capabilities
@@ -1 +0,0 @@
1
- # frozen_string_literal: true