redis_queued_locks 0.0.38 → 0.0.40

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.
data/Rakefile CHANGED
@@ -2,11 +2,20 @@
2
2
 
3
3
  require 'bundler/gem_tasks'
4
4
  require 'rspec/core/rake_task'
5
-
6
- RSpec::Core::RakeTask.new(:spec)
7
-
5
+ require 'rubocop'
8
6
  require 'rubocop/rake_task'
7
+ require 'rubocop-performance'
8
+ require 'rubocop-rspec'
9
+ require 'rubocop-rake'
10
+
11
+ RuboCop::RakeTask.new(:rubocop) do |t|
12
+ config_path = File.expand_path(File.join('.rubocop.yml'), __dir__)
13
+ t.options = ['--config', config_path]
14
+ t.requires << 'rubocop-rspec'
15
+ t.requires << 'rubocop-performance'
16
+ t.requires << 'rubocop-rake'
17
+ end
9
18
 
10
- RuboCop::RakeTask.new
19
+ RSpec::Core::RakeTask.new(:rspec)
11
20
 
12
- task default: %i[spec rubocop]
21
+ task default: :rspec
@@ -42,12 +42,12 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
42
42
 
43
43
  if log_lock_try
44
44
  run_non_critical do
45
- logger.debug(
45
+ logger.debug do
46
46
  "[redis_queued_locks.try_lock.start] " \
47
47
  "lock_key => '#{lock_key}' " \
48
48
  "queue_ttl => #{queue_ttl} " \
49
49
  "acq_id => '#{acquier_id}'"
50
- )
50
+ end
51
51
  end
52
52
  end
53
53
 
@@ -55,12 +55,12 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
55
55
  result = redis.with do |rconn|
56
56
  if log_lock_try
57
57
  run_non_critical do
58
- logger.debug(
58
+ logger.debug do
59
59
  "[redis_queued_locks.try_lock.rconn_fetched] " \
60
60
  "lock_key => '#{lock_key}' " \
61
61
  "queue_ttl => #{queue_ttl} " \
62
62
  "acq_id => '#{acquier_id}'"
63
- )
63
+ end
64
64
  end
65
65
  end
66
66
 
@@ -74,25 +74,21 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
74
74
  inter_result = :fail_fast_no_try
75
75
  else
76
76
  # Step 1: add an acquier to the lock acquirement queue
77
- res = rconn.call('ZADD', lock_key_queue, 'NX', acquier_position, acquier_id)
77
+ rconn.call('ZADD', lock_key_queue, 'NX', acquier_position, acquier_id)
78
78
 
79
79
  if log_lock_try
80
80
  run_non_critical do
81
- logger.debug(
81
+ logger.debug do
82
82
  "[redis_queued_locks.try_lock.acq_added_to_queue] " \
83
83
  "lock_key => '#{lock_key}' " \
84
84
  "queue_ttl => #{queue_ttl} " \
85
85
  "acq_id => '#{acquier_id}'"
86
- )
86
+ end
87
87
  end
88
88
  end
89
89
 
90
- RedisQueuedLocks.debug(
91
- "Step №1: добавление в очередь (#{acquier_id}). [ZADD to the queue: #{res}]"
92
- )
93
-
94
90
  # Step 2.1: drop expired acquiers from the lock queue
95
- res = rconn.call(
91
+ rconn.call(
96
92
  'ZREMRANGEBYSCORE',
97
93
  lock_key_queue,
98
94
  '-inf',
@@ -101,58 +97,44 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
101
97
 
102
98
  if log_lock_try
103
99
  run_non_critical do
104
- logger.debug(
100
+ logger.debug do
105
101
  "[redis_queued_locks.try_lock.remove_expired_acqs] " \
106
102
  "lock_key => '#{lock_key}' " \
107
103
  "queue_ttl => #{queue_ttl} " \
108
104
  "acq_id => '#{acquier_id}'"
109
- )
105
+ end
110
106
  end
111
107
  end
112
108
 
113
- RedisQueuedLocks.debug(
114
- "Step №2: дропаем из очереди просроченных ожидающих. [ZREMRANGE: #{res}]"
115
- )
116
-
117
109
  # Step 3: get the actual acquier waiting in the queue
118
110
  waiting_acquier = Array(rconn.call('ZRANGE', lock_key_queue, '0', '0')).first
119
111
 
120
112
  if log_lock_try
121
113
  run_non_critical do
122
- logger.debug(
114
+ logger.debug do
123
115
  "[redis_queued_locks.try_lock.get_first_from_queue] " \
124
116
  "lock_key => '#{lock_key}' " \
125
117
  "queue_ttl => #{queue_ttl} " \
126
118
  "acq_id => '#{acquier_id}' " \
127
119
  "first_acq_id_in_queue => '#{waiting_acquier}'"
128
- )
120
+ end
129
121
  end
130
122
  end
131
123
 
132
- RedisQueuedLocks.debug(
133
- "Step №3: какой процесс в очереди сейчас ждет. " \
134
- "[ZRANGE <следующий процесс>: #{waiting_acquier} :: <текущий процесс>: #{acquier_id}]"
135
- )
136
-
137
124
  # Step PRE-4.x: check if the request time limit is reached
138
125
  # (when the current try self-removes itself from queue (queue ttl has come))
139
126
  if waiting_acquier == nil
140
127
  if log_lock_try
141
128
  run_non_critical do
142
- logger.debug(
129
+ logger.debug do
143
130
  "[redis_queued_locks.try_lock.exit__queue_ttl_reached] " \
144
131
  "lock_key => '#{lock_key}' " \
145
132
  "queue_ttl => #{queue_ttl} " \
146
133
  "acq_id => '#{acquier_id}'"
147
- )
134
+ end
148
135
  end
149
136
  end
150
137
 
151
- RedisQueuedLocks.debug(
152
- "Step PRE-ROLLBACK №0: достигли лимита времени эквайра лока (queue ttl). выходим. " \
153
- "[Наша позиция: #{acquier_id}. queue_ttl: #{queue_ttl}]"
154
- )
155
-
156
138
  inter_result = :dead_score_reached
157
139
  # Step 4: check the actual acquier: is it ours? are we aready to lock?
158
140
  elsif waiting_acquier != acquier_id
@@ -160,59 +142,41 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
160
142
 
161
143
  if log_lock_try
162
144
  run_non_critical do
163
- logger.debug(
145
+ logger.debug do
164
146
  "[redis_queued_locks.try_lock.exit__no_first] " \
165
147
  "lock_key => '#{lock_key}' " \
166
148
  "queue_ttl => #{queue_ttl} " \
167
149
  "acq_id => '#{acquier_id}' " \
168
150
  "first_acq_id_in_queue => '#{waiting_acquier}' " \
169
151
  "<current_lock_data> => <<#{rconn.call('HGETALL', lock_key).to_h}>>"
170
- )
152
+ end
171
153
  end
172
154
  end
173
155
 
174
- RedisQueuedLocks.debug(
175
- "Step ROLLBACK №1: не одинаковые ключи. выходим. " \
176
- "[Ждет: #{waiting_acquier}. А нужен: #{acquier_id}]"
177
- )
178
-
179
156
  inter_result = :acquier_is_not_first_in_queue
180
157
  else
181
158
  # NOTE: our time has come! let's try to acquire the lock!
182
159
 
183
- # Step 5: check if the our lock is already acquired
160
+ # Step 5: find the lock -> check if the our lock is already acquired
184
161
  locked_by_acquier = rconn.call('HGET', lock_key, 'acq_id')
185
162
 
186
- # rubocop:disable Layout/LineLength
187
- RedisQueuedLocks.debug(
188
- "Ste №5: Ищем требуемый лок. " \
189
- "[HGET<#{lock_key}>: " \
190
- "#{(locked_by_acquier == nil) ? 'не занят' : "занят процессом <#{locked_by_acquier}>"}"
191
- )
192
- # rubocop:enable Layout/LineLength
193
-
194
163
  if locked_by_acquier
195
164
  # Step ROLLBACK 2: required lock is stil acquired. retry!
196
165
 
197
166
  if log_lock_try
198
167
  run_non_critical do
199
- logger.debug(
200
- "[redis_queued_locks.try_lock.exit__still_obtained] " \
168
+ logger.debug do
169
+ "[redis_queued_locks.try_lock.exit__lock_still_obtained] " \
201
170
  "lock_key => '#{lock_key}' " \
202
171
  "queue_ttl => #{queue_ttl} " \
203
172
  "acq_id => '#{acquier_id}' " \
204
173
  "first_acq_id_in_queue => '#{waiting_acquier}' " \
205
174
  "locked_by_acq_id => '#{locked_by_acquier}' " \
206
175
  "<current_lock_data> => <<#{rconn.call('HGETALL', lock_key).to_h}>>"
207
- )
176
+ end
208
177
  end
209
178
  end
210
179
 
211
- RedisQueuedLocks.debug(
212
- "Step ROLLBACK №2: Ключ уже занят. Ничего не делаем. " \
213
- "[Занят процессом: #{locked_by_acquier}]"
214
- )
215
-
216
180
  inter_result = :lock_is_still_acquired
217
181
  else
218
182
  # NOTE: required lock is free and ready to be acquired! acquire!
@@ -220,16 +184,6 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
220
184
  # Step 6.1: remove our acquier from waiting queue
221
185
  transact.call('ZREM', lock_key_queue, acquier_id)
222
186
 
223
- RedisQueuedLocks.debug(
224
- 'Step №4: Забираем наш текущий процесс из очереди. [ZREM]'
225
- )
226
-
227
- # rubocop:disable Layout/LineLength
228
- RedisQueuedLocks.debug(
229
- "===> <FINAL> Step №6: закрепляем лок за процессом [HSET<#{lock_key}>: #{acquier_id}]"
230
- )
231
- # rubocop:enable Layout/LineLength
232
-
233
187
  # Step 6.2: acquire a lock and store an info about the acquier
234
188
  transact.call(
235
189
  'HSET',
@@ -245,12 +199,12 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
245
199
 
246
200
  if log_lock_try
247
201
  run_non_critical do
248
- logger.debug(
249
- "[redis_queued_locks.try_lock.run__free_to_acquire] " \
202
+ logger.debug do
203
+ "[redis_queued_locks.try_lock.obtain__free_to_acquire] " \
250
204
  "lock_key => '#{lock_key}' " \
251
205
  "queue_ttl => #{queue_ttl} " \
252
206
  "acq_id => '#{acquier_id}'"
253
- )
207
+ end
254
208
  end
255
209
  end
256
210
  end
@@ -297,18 +251,26 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
297
251
  # rubocop:enable Metrics/MethodLength, Metrics/PerceivedComplexity
298
252
 
299
253
  # @param redis [RedisClient]
254
+ # @param logger [::Logger,#debug]
255
+ # @param lock_key [String]
300
256
  # @param lock_key_queue [String]
257
+ # @param queue_ttl [Integer]
301
258
  # @param acquier_id [String]
302
259
  # @return [Hash<Symbol,Any>] Format: { ok: true/false, result: Any }
303
260
  #
304
261
  # @api private
305
262
  # @since 0.1.0
306
- def dequeue_from_lock_queue(redis, lock_key_queue, acquier_id)
263
+ def dequeue_from_lock_queue(redis, logger, lock_key, lock_key_queue, queue_ttl, acquier_id)
307
264
  result = redis.call('ZREM', lock_key_queue, acquier_id)
308
265
 
309
- RedisQueuedLocks.debug(
310
- "Step ~ [СМЕРТЬ ПРОЦЕССА]: [#{acquier_id} :: #{lock_key_queue}] РЕЗУЛЬТАТ: #{result}"
311
- )
266
+ run_non_critical do
267
+ logger.debug do
268
+ "[redis_queued_locks.fail_fast_or_limits_reached__dequeue] " \
269
+ "lock_key => '#{lock_key}' " \
270
+ "queue_ttl => '#{queue_ttl}' " \
271
+ "acq_id => '#{acquier_id}'"
272
+ end
273
+ end
312
274
 
313
275
  RedisQueuedLocks::Data[ok: true, result: result]
314
276
  end
@@ -40,12 +40,12 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldWithExpire
40
40
  end
41
41
  ensure
42
42
  run_non_critical do
43
- logger.debug(
43
+ logger.debug do
44
44
  "[redis_queued_locks.expire_lock] " \
45
45
  "lock_key => '#{lock_key}' " \
46
46
  "queue_ttl => #{queue_ttl} " \
47
47
  "acq_id => '#{acquier_id}'"
48
- )
48
+ end
49
49
  end
50
50
  redis.call('EXPIRE', lock_key, '0')
51
51
  end
@@ -23,11 +23,11 @@ module RedisQueuedLocks::Acquier::AcquireLock
23
23
  # @since 0.1.0
24
24
  extend RedisQueuedLocks::Utilities
25
25
 
26
- # @return [Integer] Redis expiration error (in milliseconds).
26
+ # @return [Integer] Redis time error (in milliseconds).
27
27
  #
28
28
  # @api private
29
29
  # @since 0.1.0
30
- REDIS_EXPIRE_ERROR = 1
30
+ REDIS_TIMESHIFT_ERROR = 2
31
31
 
32
32
  class << self
33
33
  # @param redis [RedisClient]
@@ -146,9 +146,6 @@ module RedisQueuedLocks::Acquier::AcquireLock
146
146
  ractor_id,
147
147
  identity
148
148
  )
149
- # NOTE:
150
- # - think aobut the redis expiration error
151
- # - (ttl - REDIS_EXPIRE_ERROR).yield_self { |val| (val == 0) ? ttl : val }
152
149
  lock_ttl = ttl
153
150
  lock_key = RedisQueuedLocks::Resource.prepare_lock_key(lock_name)
154
151
  lock_key_queue = RedisQueuedLocks::Resource.prepare_lock_queue(lock_name)
@@ -165,15 +162,24 @@ module RedisQueuedLocks::Acquier::AcquireLock
165
162
  hold_time: nil, # NOTE: in milliseconds
166
163
  rel_time: nil # NOTE: in milliseconds
167
164
  }
168
- acq_dequeue = -> { dequeue_from_lock_queue(redis, lock_key_queue, acquier_id) }
165
+
166
+ acq_dequeue = proc do
167
+ dequeue_from_lock_queue(
168
+ redis, logger,
169
+ lock_key,
170
+ lock_key_queue,
171
+ queue_ttl,
172
+ acquier_id
173
+ )
174
+ end
169
175
 
170
176
  run_non_critical do
171
- logger.debug(
177
+ logger.debug do
172
178
  "[redis_queued_locks.start_lock_obtaining] " \
173
179
  "lock_key => '#{lock_key}' " \
174
180
  "queue_ttl => #{queue_ttl} " \
175
181
  "acq_id => '#{acquier_id}'"
176
- )
182
+ end
177
183
  end
178
184
 
179
185
  # Step 2: try to lock with timeout
@@ -183,12 +189,12 @@ module RedisQueuedLocks::Acquier::AcquireLock
183
189
  # Step 2.1: caclically try to obtain the lock
184
190
  while acq_process[:should_try]
185
191
  run_non_critical do
186
- logger.debug(
192
+ logger.debug do
187
193
  "[redis_queued_locks.start_try_to_lock_cycle] " \
188
194
  "lock_key => '#{lock_key}' " \
189
195
  "queue_ttl => #{queue_ttl} " \
190
196
  "acq_id => '{#{acquier_id}'"
191
- )
197
+ end
192
198
  end
193
199
 
194
200
  # Step 2.X: check the actual score: is it in queue ttl limit or not?
@@ -197,12 +203,12 @@ module RedisQueuedLocks::Acquier::AcquireLock
197
203
  acquier_position = RedisQueuedLocks::Resource.calc_initial_acquier_position
198
204
 
199
205
  run_non_critical do
200
- logger.debug(
206
+ logger.debug do
201
207
  "[redis_queued_locks.dead_score_reached__reset_acquier_position] " \
202
208
  "lock_key => '#{lock_key} " \
203
209
  "queue_ttl => #{queue_ttl} " \
204
210
  "acq_id => '#{acquier_id}'"
205
- )
211
+ end
206
212
  end
207
213
  end
208
214
 
@@ -230,13 +236,13 @@ module RedisQueuedLocks::Acquier::AcquireLock
230
236
  # Step 2.1: analyze an acquirement attempt
231
237
  if ok
232
238
  run_non_critical do
233
- logger.debug(
239
+ logger.debug do
234
240
  "[redis_queued_locks.lock_obtained] " \
235
241
  "lock_key => '#{result[:lock_key]}' " \
236
242
  "queue_ttl => #{queue_ttl} " \
237
243
  "acq_id => '#{acquier_id}' " \
238
244
  "acq_time => #{acq_time} (ms)"
239
- )
245
+ end
240
246
  end
241
247
 
242
248
  # Step X (instrumentation): lock obtained
@@ -315,7 +321,11 @@ module RedisQueuedLocks::Acquier::AcquireLock
315
321
  if block_given?
316
322
  begin
317
323
  yield_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
318
- ttl_shift = ((yield_time - acq_process[:acq_end_time]) * 1000).ceil(2)
324
+
325
+ ttl_shift = (
326
+ (yield_time - acq_process[:acq_end_time]) * 1000 - REDIS_TIMESHIFT_ERROR
327
+ ).ceil(2)
328
+
319
329
  yield_with_expire(
320
330
  redis,
321
331
  logger,
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ module RedisQueuedLocks::Acquier::ClearDeadRequests
6
+ class << self
7
+ # @param redis_client [RedisClient]
8
+ # @param scan_size [Integer]
9
+ # @param dead_ttl [Integer] In milliseconds
10
+ # @param logger [::Logger,#debug]
11
+ # @param instrumenter [#notify]
12
+ # @param instrument [NilClass,Any]
13
+ # @return [Hash<Symbol,Boolean|Hash<Symbol,Set<String>>>]
14
+ #
15
+ # @api private
16
+ # @since 0.1.0
17
+ def clear_dead_requests(redis_client, scan_size, dead_ttl, logger, instrumenter, instrument)
18
+ dead_score = RedisQueuedLocks::Resource.acquier_dead_score(dead_ttl / 1000.0)
19
+
20
+ result = Set.new.tap do |processed_queues|
21
+ redis_client.with do |rconn|
22
+ each_lock_queue(rconn, scan_size) do |lock_queue|
23
+ rconn.call('ZREMRANGEBYSCORE', lock_queue, '-inf', dead_score)
24
+ processed_queues << lock_queue
25
+ end
26
+ end
27
+ end
28
+
29
+ RedisQueuedLocks::Data[ok: true, result: { processed_queues: result }]
30
+ end
31
+
32
+ private
33
+
34
+ # @param redis_client [RedisClient]
35
+ # @param scan_size [Integer]
36
+ # @yield [lock_queue]
37
+ # @yieldparam lock_queue [String]
38
+ # @yieldreturn [void]
39
+ # @return [Enumerator]
40
+ #
41
+ # @api private
42
+ # @since 0.1.0
43
+ def each_lock_queue(redis_client, scan_size, &block)
44
+ redis_client.scan(
45
+ 'MATCH',
46
+ RedisQueuedLocks::Resource::LOCK_QUEUE_PATTERN,
47
+ count: scan_size,
48
+ &block
49
+ )
50
+ end
51
+ end
52
+ end
@@ -3,17 +3,36 @@
3
3
  # @api private
4
4
  # @since 0.1.0
5
5
  module RedisQueuedLocks::Acquier::ExtendLockTTL
6
+ # @return [String]
7
+ #
8
+ # @api private
9
+ # @since 0.1.0
10
+ EXTEND_LOCK_PTTL = <<~LUA_SCRIPT.strip.tr("\n", '').freeze
11
+ local new_lock_pttl = redis.call("PTTL", KEYS[1]) + ARGV[1];
12
+ return redis.call("PEXPIRE", KEYS[1], new_lock_pttl);
13
+ LUA_SCRIPT
14
+
6
15
  class << self
7
16
  # @param redis_client [RedisClient]
8
17
  # @param lock_name [String]
9
18
  # @param milliseconds [Integer]
10
19
  # @param logger [::Logger,#debug]
11
- # @return [?]
20
+ # @return [Hash<Symbol,Boolean|Symbol>]
12
21
  #
13
22
  # @api private
14
23
  # @since 0.1.0
15
24
  def extend_lock_ttl(redis_client, lock_name, milliseconds, logger)
16
- # TODO: realize
25
+ lock_key = RedisQueuedLocks::Resource.prepare_lock_key(lock_name)
26
+
27
+ # NOTE: EVAL signature -> <lua script>, (number of keys), *(keys), *(arguments)
28
+ result = redis_client.call('EVAL', EXTEND_LOCK_PTTL, 1, lock_key, milliseconds)
29
+ # TODO: upload scripts to the redis
30
+
31
+ if result == 1
32
+ RedisQueuedLocks::Data[ok: true, result: :ttl_extended]
33
+ else
34
+ RedisQueuedLocks::Data[ok: false, result: :async_expire_or_no_lock]
35
+ end
17
36
  end
18
37
  end
19
38
  end
@@ -21,9 +21,9 @@ module RedisQueuedLocks::Acquier::LockInfo
21
21
  def lock_info(redis_client, lock_name)
22
22
  lock_key = RedisQueuedLocks::Resource.prepare_lock_key(lock_name)
23
23
 
24
- result = redis_client.multi(watch: [lock_key]) do |transact|
25
- transact.call('HGETALL', lock_key)
26
- transact.call('PTTL', lock_key)
24
+ result = redis_client.pipelined do |pipeline|
25
+ pipeline.call('HGETALL', lock_key)
26
+ pipeline.call('PTTL', lock_key)
27
27
  end
28
28
 
29
29
  if result == nil
@@ -12,8 +12,10 @@ module RedisQueuedLocks::Acquier::Locks
12
12
  # @api private
13
13
  # @since 0.1.0
14
14
  def locks(redis_client, scan_size:, with_info:)
15
- lock_keys = scan_locks(redis_client, scan_size)
16
- with_info ? extract_locks_info(redis_client, lock_keys) : lock_keys
15
+ redis_client.with do |rconn|
16
+ lock_keys = scan_locks(rconn, scan_size)
17
+ with_info ? extract_locks_info(rconn, lock_keys) : lock_keys
18
+ end
17
19
  end
18
20
 
19
21
  private
@@ -50,9 +52,9 @@ module RedisQueuedLocks::Acquier::Locks
50
52
  # Step X: iterate each lock and extract their info
51
53
  lock_keys.each do |lock_key|
52
54
  # Step 1: extract lock info from redis
53
- lock_info = redis_client.multi(watch: [lock_key]) do |transact|
54
- transact.call('HGETALL', lock_key)
55
- transact.call('PTTL', lock_key)
55
+ lock_info = redis_client.pipelined do |pipeline|
56
+ pipeline.call('HGETALL', lock_key)
57
+ pipeline.call('PTTL', lock_key)
56
58
  end.yield_self do |result| # Step 2: format the result
57
59
  # Step 2.X: lock is released
58
60
  if result == nil
@@ -12,8 +12,10 @@ module RedisQueuedLocks::Acquier::Queues
12
12
  # @api private
13
13
  # @since 0.1.0
14
14
  def queues(redis_client, scan_size:, with_info:)
15
- lock_queues = scan_queues(redis_client, scan_size)
16
- with_info ? extract_queues_info(redis_client, lock_queues) : lock_queues
15
+ redis_client.with do |rconn|
16
+ lock_queues = scan_queues(rconn, scan_size)
17
+ with_info ? extract_queues_info(rconn, lock_queues) : lock_queues
18
+ end
17
19
  end
18
20
 
19
21
  private
@@ -15,20 +15,23 @@ module RedisQueuedLocks::Acquier::ReleaseAllLocks
15
15
  # Redis connection client.
16
16
  # @param batch_size [Integer]
17
17
  # The number of lock keys that should be released in a time.
18
- # @param isntrumenter [#notify]
19
- # See RedisQueuedLocks::Instrument::ActiveSupport for example.
20
18
  # @param logger [::Logger,#debug]
21
19
  # - Logger object used from `configuration` layer (see config[:logger]);
22
20
  # - See RedisQueuedLocks::Logging::VoidLogger for example;
21
+ # @param isntrumenter [#notify]
22
+ # See RedisQueuedLocks::Instrument::ActiveSupport for example.
23
+ # @option instrument [NilClass,Any]
24
+ # - Custom instrumentation data wich will be passed to the instrumenter's payload
25
+ # with :instrument key;
23
26
  # @return [RedisQueuedLocks::Data,Hash<Symbol,Any>]
24
- # Format: { ok: true/false, result: Hash<Symbol,Numeric> }
27
+ # Format: { ok: true, result: Hash<Symbol,Numeric> }
25
28
  #
26
29
  # @api private
27
30
  # @since 0.1.0
28
- def release_all_locks(redis, batch_size, instrumenter, logger)
31
+ def release_all_locks(redis, batch_size, logger, instrumenter, instrument)
29
32
  rel_start_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
30
33
  fully_release_all_locks(redis, batch_size) => { ok:, result: }
31
- time_at = Time.now.to_i
34
+ time_at = Time.now.to_f
32
35
  rel_end_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
33
36
  rel_time = ((rel_end_time - rel_start_time) * 1_000).ceil(2)
34
37
 
@@ -36,13 +39,13 @@ module RedisQueuedLocks::Acquier::ReleaseAllLocks
36
39
  instrumenter.notify('redis_queued_locks.explicit_all_locks_release', {
37
40
  at: time_at,
38
41
  rel_time: rel_time,
39
- rel_keys: result[:rel_keys]
42
+ rel_key_cnt: result[:rel_key_cnt]
40
43
  })
41
44
  end
42
45
 
43
46
  RedisQueuedLocks::Data[
44
47
  ok: true,
45
- result: { rel_key_cnt: result[:rel_keys], rel_time: rel_time }
48
+ result: { rel_key_cnt: result[:rel_key_cnt], rel_time: rel_time }
46
49
  ]
47
50
  end
48
51
 
@@ -52,7 +55,8 @@ module RedisQueuedLocks::Acquier::ReleaseAllLocks
52
55
  #
53
56
  # @param redis [RedisClient]
54
57
  # @param batch_size [Integer]
55
- # @return [RedisQueuedLocks::Data,Hash<Symbol,Any>] Format: { ok: true/false, result: Any }
58
+ # @return [RedisQueuedLocks::Data,Hash<Symbol,Boolean|Hash<Symbol,Integer>>]
59
+ # - Exmaple: { ok: true, result: { rel_key_cnt: 12345 } }
56
60
  #
57
61
  # @api private
58
62
  # @since 0.1.0
@@ -66,8 +70,7 @@ module RedisQueuedLocks::Acquier::ReleaseAllLocks
66
70
  count: batch_size
67
71
  ) do |lock_queue|
68
72
  # TODO: reduce unnecessary iterations
69
- pipeline.call('ZREMRANGEBYSCORE', lock_queue, '-inf', '+inf')
70
- pipeline.call('EXPIRE', RedisQueuedLocks::Resource.lock_key_from_queue(lock_queue), '0')
73
+ pipeline.call('EXPIRE', lock_queue, '0')
71
74
  end
72
75
 
73
76
  # Step B: release all locks
@@ -82,9 +85,7 @@ module RedisQueuedLocks::Acquier::ReleaseAllLocks
82
85
  end
83
86
  end
84
87
 
85
- rel_keys = result.count { |red_res| red_res == 0 }
86
-
87
- RedisQueuedLocks::Data[ok: true, result: { rel_keys: rel_keys }]
88
+ RedisQueuedLocks::Data[ok: true, result: { rel_key_cnt: result.sum }]
88
89
  end
89
90
  end
90
91
  end