redis_queued_locks 0.0.38 → 0.0.40

Sign up to get free protection for your applications and to get access to all the features.
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