redis_queued_locks 1.20.0 → 1.21.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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/project-overview.md +35 -13
  3. data/.claude/rules/acquirer.md +10 -9
  4. data/.claude/rules/logic.md +28 -5
  5. data/.claude/rules/swarm.md +2 -2
  6. data/.claude/rules/tests.md +6 -3
  7. data/.claude/rules/visitors.md +9 -10
  8. data/.claude/skills/rql-code-review/SKILL.md +24 -10
  9. data/CHANGELOG.md +126 -0
  10. data/CLAUDE.md +2 -1
  11. data/README.md +245 -70
  12. data/lib/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +1 -0
  13. data/lib/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rb +42 -0
  14. data/lib/redis_queued_locks/acquirer/acquire_lock/log_visitor.rb +45 -0
  15. data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rb +1 -0
  16. data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rb +12 -1
  17. data/lib/redis_queued_locks/acquirer/acquire_lock/with_acq_timeout.rb +2 -2
  18. data/lib/redis_queued_locks/acquirer/acquire_lock/yield_expire/log_visitor.rb +1 -0
  19. data/lib/redis_queued_locks/acquirer/acquire_lock/yield_expire.rb +5 -5
  20. data/lib/redis_queued_locks/acquirer/acquire_lock.rb +111 -24
  21. data/lib/redis_queued_locks/acquirer/clear_dead_requests.rb +86 -8
  22. data/lib/redis_queued_locks/acquirer/extend_lock_ttl.rb +122 -12
  23. data/lib/redis_queued_locks/acquirer/is_locked.rb +0 -1
  24. data/lib/redis_queued_locks/acquirer/is_queued.rb +0 -1
  25. data/lib/redis_queued_locks/acquirer/keys.rb +10 -1
  26. data/lib/redis_queued_locks/acquirer/lock_info.rb +31 -39
  27. data/lib/redis_queued_locks/acquirer/lock_series_poc/instr_visitor.rb +3 -2
  28. data/lib/redis_queued_locks/acquirer/lock_series_poc/log_visitor.rb +5 -4
  29. data/lib/redis_queued_locks/acquirer/lock_series_poc.rb +55 -15
  30. data/lib/redis_queued_locks/acquirer/locks.rb +26 -9
  31. data/lib/redis_queued_locks/acquirer/queue_info.rb +0 -1
  32. data/lib/redis_queued_locks/acquirer/queues.rb +10 -1
  33. data/lib/redis_queued_locks/acquirer/reindex_locks.rb +117 -4
  34. data/lib/redis_queued_locks/acquirer/release_all_locks.rb +31 -4
  35. data/lib/redis_queued_locks/acquirer/release_lock.rb +33 -7
  36. data/lib/redis_queued_locks/acquirer/release_locks_of.rb +39 -4
  37. data/lib/redis_queued_locks/acquirer/release_read_lock.rb +22 -3
  38. data/lib/redis_queued_locks/client.rb +82 -40
  39. data/lib/redis_queued_locks/config.rb +12 -13
  40. data/lib/redis_queued_locks/errors.rb +34 -4
  41. data/lib/redis_queued_locks/instrument/sampler.rb +4 -7
  42. data/lib/redis_queued_locks/logging/sampler.rb +4 -8
  43. data/lib/redis_queued_locks/resource.rb +14 -4
  44. data/lib/redis_queued_locks/swarm/flush_zombies.rb +1 -0
  45. data/lib/redis_queued_locks/swarm/redis_client_builder.rb +8 -4
  46. data/lib/redis_queued_locks/swarm/swarm_element/threaded.rb +3 -2
  47. data/lib/redis_queued_locks/swarm.rb +86 -5
  48. data/lib/redis_queued_locks/utilities.rb +1 -1
  49. data/lib/redis_queued_locks/version.rb +2 -2
  50. data/sig/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rbs +14 -0
  51. data/sig/redis_queued_locks/acquirer/acquire_lock/log_visitor.rbs +13 -0
  52. data/sig/redis_queued_locks/acquirer/acquire_lock/yield_expire.rbs +2 -2
  53. data/sig/redis_queued_locks/acquirer/acquire_lock.rbs +1 -1
  54. data/sig/redis_queued_locks/acquirer/clear_dead_requests.rbs +9 -0
  55. data/sig/redis_queued_locks/acquirer/extend_lock_ttl.rbs +15 -2
  56. data/sig/redis_queued_locks/acquirer/reindex_locks.rbs +22 -1
  57. data/sig/redis_queued_locks/acquirer/release_lock.rbs +3 -2
  58. data/sig/redis_queued_locks/acquirer/release_read_lock.rbs +1 -1
  59. data/sig/redis_queued_locks/client.rbs +14 -3
  60. data/sig/redis_queued_locks/errors.rbs +5 -2
  61. data/sig/redis_queued_locks/instrument/sampler.rbs +0 -2
  62. data/sig/redis_queued_locks/logging/sampler.rbs +0 -2
  63. data/sig/redis_queued_locks/resource.rbs +1 -1
  64. data/sig/vendor/redis_client.rbs +1 -0
  65. metadata +1 -1
@@ -2,7 +2,13 @@
2
2
 
3
3
  # @api private
4
4
  # @since 1.20.0
5
+ # @version 1.21.0
6
+ # rubocop:disable Metrics/ModuleLength
5
7
  module RedisQueuedLocks::Acquirer::ReindexLocks
8
+ # @since 1.21.0
9
+ extend RedisQueuedLocks::Utilities
10
+
11
+ # rubocop:disable Metrics/ClassLength
6
12
  class << self
7
13
  # Adds the lock keys without the lock index entry (keys of older RQL versions created before
8
14
  # the lock index) to the lock index (`RedisQueuedLocks::Resource::LOCK_INDEX_KEY`):
@@ -16,18 +22,125 @@ module RedisQueuedLocks::Acquirer::ReindexLocks
16
22
  # - keys without TTL (unreachable for RQL keys) are indexed forever (`+inf` score);
17
23
  # - the index score is never decreased (`ZADD GT`): the operation is idempotent and can be
18
24
  # invoked at any time (keys of the current RQL version are indexed already);
25
+ # - the operation is reported with one log and one instrumentation event
26
+ # (`redis_queued_locks.reindex_locks`) with the time of the whole operation;
19
27
  #
20
28
  # @param redis_client [RedisClient]
21
29
  # @param scan_size [Integer]
22
30
  # @param queue_ttl [Integer] TTL of the lock queues without TTL (in seconds).
23
31
  # @param lock_index_grace_period [Integer]
24
32
  # The lock index score margin over the key lifetime (in milliseconds).
33
+ # @param logger [::Logger,#debug]
34
+ # @param instrumenter [#notify]
35
+ # @param instrument [NilClass,Any]
36
+ # @param log_sampling_enabled [Boolean]
37
+ # @param log_sampling_percent [Integer]
38
+ # @param log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
39
+ # @param log_sample_this [Boolean]
40
+ # @param instr_sampling_enabled [Boolean]
41
+ # @param instr_sampling_percent [Integer]
42
+ # @param instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
43
+ # @param instr_sample_this [Boolean]
25
44
  # @return [Hash<Symbol,Boolean|Hash<Symbol,Integer>>]
26
45
  # Format: { ok: true, result: { idx_key_cnt: Integer } } (the number of indexed keys)
27
46
  #
28
47
  # @api private
29
48
  # @since 1.20.0
30
- def reindex_locks(redis_client, scan_size, queue_ttl, lock_index_grace_period)
49
+ # @version 1.21.0
50
+ # rubocop:disable Metrics/MethodLength
51
+ def reindex_locks(
52
+ redis_client,
53
+ scan_size,
54
+ queue_ttl,
55
+ lock_index_grace_period,
56
+ logger,
57
+ instrumenter,
58
+ instrument,
59
+ log_sampling_enabled,
60
+ log_sampling_percent,
61
+ log_sampler,
62
+ log_sample_this,
63
+ instr_sampling_enabled,
64
+ instr_sampling_percent,
65
+ instr_sampler,
66
+ instr_sample_this
67
+ )
68
+ # NOTE: (arguments) the same ranges as the config keys: zero/negative sizes fail SCAN
69
+ # (`COUNT 0`), a non-positive queue ttl expires the lock queues without TTL at once;
70
+ if !scan_size.is_a?(::Integer) || scan_size <= 0
71
+ raise(
72
+ RedisQueuedLocks::ArgumentError,
73
+ "`:scan_size` argument should be a positive Integer, got #{scan_size.inspect}."
74
+ )
75
+ end
76
+ if !queue_ttl.is_a?(::Integer) || queue_ttl <= 0
77
+ raise(
78
+ RedisQueuedLocks::ArgumentError,
79
+ "`:queue_ttl` argument should be a positive Integer, got #{queue_ttl.inspect}."
80
+ )
81
+ end
82
+ if !lock_index_grace_period.is_a?(::Integer) || lock_index_grace_period < 0
83
+ raise(
84
+ RedisQueuedLocks::ArgumentError,
85
+ "`:lock_index_grace_period` argument should be a non-negative Integer, " \
86
+ "got #{lock_index_grace_period.inspect}."
87
+ )
88
+ end
89
+
90
+ idx_start_time = clock_gettime
91
+ idx_key_cnt = fully_reindex_locks(redis_client, scan_size, queue_ttl, lock_index_grace_period)
92
+ time_at = Time.now.to_f
93
+ idx_end_time = clock_gettime
94
+ idx_time = ((idx_end_time - idx_start_time) / 1_000.0).ceil(2)
95
+
96
+ log_sampled = RedisQueuedLocks::Logging.should_log?(
97
+ log_sampling_enabled,
98
+ log_sample_this,
99
+ log_sampling_percent,
100
+ log_sampler
101
+ )
102
+ instr_sampled = RedisQueuedLocks::Instrument.should_instrument?(
103
+ instr_sampling_enabled,
104
+ instr_sample_this,
105
+ instr_sampling_percent,
106
+ instr_sampler
107
+ )
108
+
109
+ run_non_critical do
110
+ logger.debug do
111
+ "[redis_queued_locks.reindex_locks] " \
112
+ "idx_key_cnt => #{idx_key_cnt} " \
113
+ "idx_time => #{idx_time} " \
114
+ "at => #{time_at}"
115
+ end
116
+ end if log_sampled
117
+
118
+ run_non_critical do
119
+ instrumenter.notify('redis_queued_locks.reindex_locks', {
120
+ idx_key_cnt: idx_key_cnt,
121
+ idx_time: idx_time,
122
+ at: time_at,
123
+ instrument: instrument
124
+ })
125
+ end if instr_sampled
126
+
127
+ { ok: true, result: { idx_key_cnt: } }
128
+ end
129
+ # rubocop:enable Metrics/MethodLength
130
+
131
+ private
132
+
133
+ # Adds the lock keys without the lock index entry to the lock index (see `reindex_locks`).
134
+ #
135
+ # @param redis_client [RedisClient]
136
+ # @param scan_size [Integer]
137
+ # @param queue_ttl [Integer] TTL of the lock queues without TTL (in seconds).
138
+ # @param lock_index_grace_period [Integer]
139
+ # @return [Integer] The number of indexed keys.
140
+ #
141
+ # @api private
142
+ # @since 1.21.0
143
+ def fully_reindex_locks(redis_client, scan_size, queue_ttl, lock_index_grace_period)
31
144
  # NOTE: `ceil` - queue ttl can be passed as a Float (in seconds), PEXPIRE requires Integer
32
145
  queue_pttl = (queue_ttl * 1_000).ceil
33
146
  idx_key_cnt = 0
@@ -61,11 +174,9 @@ module RedisQueuedLocks::Acquirer::ReindexLocks
61
174
  end
62
175
  end
63
176
 
64
- { ok: true, result: { idx_key_cnt: } }
177
+ idx_key_cnt
65
178
  end
66
179
 
67
- private
68
-
69
180
  # Adds the given batch of lock keys to the lock index (two round trips: key TTLs, then
70
181
  # the index entries).
71
182
  #
@@ -137,4 +248,6 @@ module RedisQueuedLocks::Acquirer::ReindexLocks
137
248
  1
138
249
  end
139
250
  end
251
+ # rubocop:enable Metrics/ClassLength
140
252
  end
253
+ # rubocop:enable Metrics/ModuleLength
@@ -39,7 +39,7 @@ module RedisQueuedLocks::Acquirer::ReleaseAllLocks
39
39
  # - works in tandem with <config['log_sampling_percent']> and <config['log_sampler']>;
40
40
  # @param log_sampling_percent [Integer]
41
41
  # - the percent of cases that should be logged;
42
- # - take an effect when <config['log_sampling_enalbed']> is true;
42
+ # - take an effect when <config['log_sampling_enabled']> is true;
43
43
  # - works in tandem with <config['log_sampling_enabled']> and <config['log_sampler']> configs;
44
44
  # @param log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
45
45
  # - percent-based log sampler that decides should be RQL case logged or not;
@@ -60,7 +60,7 @@ module RedisQueuedLocks::Acquirer::ReleaseAllLocks
60
60
  # - works in tandem with <config['instr_sampling_percent']> and <config['instr_sampler']>;
61
61
  # @param instr_sampling_percent [Integer]
62
62
  # - the percent of cases that should be instrumented;
63
- # - take an effect when <config['instr_sampling_enalbed']> is true;
63
+ # - take an effect when <config['instr_sampling_enabled']> is true;
64
64
  # - works in tandem with <config['instr_sampling_enabled']>
65
65
  # and <config['instr_sampler']> configs;
66
66
  # @param instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
@@ -81,7 +81,8 @@ module RedisQueuedLocks::Acquirer::ReleaseAllLocks
81
81
  #
82
82
  # @api private
83
83
  # @since 1.0.0
84
- # @version 1.20.0
84
+ # @version 1.21.0
85
+ # rubocop:disable Metrics/MethodLength
85
86
  def release_all_locks(
86
87
  redis,
87
88
  batch_size,
@@ -98,6 +99,15 @@ module RedisQueuedLocks::Acquirer::ReleaseAllLocks
98
99
  instr_sampler,
99
100
  instr_sample_this
100
101
  )
102
+ # NOTE: (arguments) the same ranges as the config keys: zero/negative sizes fail SCAN/ZSCAN
103
+ # (`COUNT 0`) and the batching (`each_slice(0)`);
104
+ if !batch_size.is_a?(::Integer) || batch_size <= 0
105
+ raise(
106
+ RedisQueuedLocks::ArgumentError,
107
+ "`:batch_size` argument should be a positive Integer, got #{batch_size.inspect}."
108
+ )
109
+ end
110
+
101
111
  rel_start_time = clock_gettime
102
112
  # steep:ignore:start
103
113
  fully_release_all_locks(redis, batch_size, lock_index_enabled) => { ok:, result: }
@@ -110,6 +120,12 @@ module RedisQueuedLocks::Acquirer::ReleaseAllLocks
110
120
  rel_end_time = clock_gettime
111
121
  rel_time = ((rel_end_time - rel_start_time) / 1_000.0).ceil(2)
112
122
 
123
+ log_sampled = RedisQueuedLocks::Logging.should_log?(
124
+ log_sampling_enabled,
125
+ log_sample_this,
126
+ log_sampling_percent,
127
+ log_sampler
128
+ )
113
129
  instr_sampled = RedisQueuedLocks::Instrument.should_instrument?(
114
130
  instr_sampling_enabled,
115
131
  instr_sample_this,
@@ -117,11 +133,21 @@ module RedisQueuedLocks::Acquirer::ReleaseAllLocks
117
133
  instr_sampler
118
134
  )
119
135
 
136
+ run_non_critical do
137
+ logger.debug do
138
+ "[redis_queued_locks.explicit_all_locks_release] " \
139
+ "at => #{time_at} " \
140
+ "rel_time => #{rel_time} " \
141
+ "rel_key_cnt => #{result[:rel_key_cnt]}"
142
+ end
143
+ end if log_sampled
144
+
120
145
  run_non_critical do
121
146
  instrumenter.notify('redis_queued_locks.explicit_all_locks_release', {
122
147
  at: time_at,
123
148
  rel_time: rel_time,
124
- rel_key_cnt: result[:rel_key_cnt]
149
+ rel_key_cnt: result[:rel_key_cnt],
150
+ instrument: instrument
125
151
  })
126
152
  end if instr_sampled
127
153
 
@@ -130,6 +156,7 @@ module RedisQueuedLocks::Acquirer::ReleaseAllLocks
130
156
  result: { rel_key_cnt: result[:rel_key_cnt], rel_time: rel_time }
131
157
  }
132
158
  end
159
+ # rubocop:enable Metrics/MethodLength
133
160
 
134
161
  private
135
162
 
@@ -2,10 +2,13 @@
2
2
 
3
3
  # @api private
4
4
  # @since 1.0.0
5
+ # @version 1.21.0
6
+ # rubocop:disable Metrics/ModuleLength
5
7
  module RedisQueuedLocks::Acquirer::ReleaseLock
6
8
  # @since 1.0.0
7
9
  extend RedisQueuedLocks::Utilities
8
10
 
11
+ # rubocop:disable Metrics/ClassLength
9
12
  class << self
10
13
  # Release the concrete lock:
11
14
  # - 1. clear lock queue: al; related processes released
@@ -22,18 +25,21 @@ module RedisQueuedLocks::Acquirer::ReleaseLock
22
25
  # The lock name that should be released.
23
26
  # @param lock_index_enabled [Boolean]
24
27
  # Drop the lock name from the lock index (the enabled lock index).
25
- # @param instrumenter [#notify]
26
- # See RedisQueuedLocks::Instrument::ActiveSupport for example.
27
28
  # @param logger [::Logger,#debug]
28
29
  # - Logger object used from `configuration` layer (see config['logger']);
29
30
  # - See RedisQueuedLocks::Logging::VoidLogger for example;
31
+ # @param instrumenter [#notify]
32
+ # See RedisQueuedLocks::Instrument::ActiveSupport for example.
33
+ # @param instrument [NilClass,Any]
34
+ # - Custom instrumentation data wich will be passed to the instrumenter's payload
35
+ # with :instrument key;
30
36
  # @param log_sampling_enabled [Boolean]
31
37
  # - enables <log sampling>: only the configured percent of RQL cases will be logged;
32
38
  # - disabled by default;
33
39
  # - works in tandem with <config['log_sampling_percent']> and <config['log_sampler']>;
34
40
  # @param log_sampling_percent [Integer]
35
41
  # - the percent of cases that should be logged;
36
- # - take an effect when <config['log_sampling_enalbed']> is true;
42
+ # - take an effect when <config['log_sampling_enabled']> is true;
37
43
  # - works in tandem with <config['log_sampling_enabled']> and <config['log_sampler']> configs;
38
44
  # @param log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
39
45
  # - percent-based log sampler that decides should be RQL case logged or not;
@@ -54,7 +60,7 @@ module RedisQueuedLocks::Acquirer::ReleaseLock
54
60
  # - works in tandem with <config['instr_sampling_percent']> and <config['instr_sampler']>;
55
61
  # @param instr_sampling_percent [Integer]
56
62
  # - the percent of cases that should be instrumented;
57
- # - take an effect when <config['instr_sampling_enalbed']> is true;
63
+ # - take an effect when <config['instr_sampling_enabled']> is true;
58
64
  # - works in tandem with <config['instr_sampling_enabled']>
59
65
  # and <config['instr_sampler']> configs;
60
66
  # @param instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
@@ -75,14 +81,15 @@ module RedisQueuedLocks::Acquirer::ReleaseLock
75
81
  #
76
82
  # @api private
77
83
  # @since 1.0.0
78
- # @version 1.20.0
84
+ # @version 1.21.0
79
85
  # rubocop:disable Metrics/MethodLength
80
86
  def release_lock(
81
87
  redis,
82
88
  lock_name,
83
89
  lock_index_enabled,
84
- instrumenter,
85
90
  logger,
91
+ instrumenter,
92
+ instrument,
86
93
  log_sampling_enabled,
87
94
  log_sampling_percent,
88
95
  log_sampler,
@@ -112,6 +119,12 @@ module RedisQueuedLocks::Acquirer::ReleaseLock
112
119
  rel_end_time = clock_gettime
113
120
  rel_time = ((rel_end_time - rel_start_time) / 1_000.0).ceil(2)
114
121
 
122
+ log_sampled = RedisQueuedLocks::Logging.should_log?(
123
+ log_sampling_enabled,
124
+ log_sample_this,
125
+ log_sampling_percent,
126
+ log_sampler
127
+ )
115
128
  instr_sampled = RedisQueuedLocks::Instrument.should_instrument?(
116
129
  instr_sampling_enabled,
117
130
  instr_sample_this,
@@ -119,12 +132,23 @@ module RedisQueuedLocks::Acquirer::ReleaseLock
119
132
  instr_sampler
120
133
  )
121
134
 
135
+ run_non_critical do
136
+ logger.debug do
137
+ "[redis_queued_locks.explicit_lock_release] " \
138
+ "lock_key => '#{lock_key}' " \
139
+ "lock_key_queue => '#{lock_key_queue}' " \
140
+ "rel_time => #{rel_time} " \
141
+ "at => #{time_at}"
142
+ end
143
+ end if log_sampled
144
+
122
145
  run_non_critical do
123
146
  instrumenter.notify('redis_queued_locks.explicit_lock_release', {
124
147
  lock_key: lock_key,
125
148
  lock_key_queue: lock_key_queue,
126
149
  rel_time: rel_time,
127
- at: time_at
150
+ at: time_at,
151
+ instrument: instrument
128
152
  })
129
153
  end if instr_sampled
130
154
 
@@ -229,4 +253,6 @@ module RedisQueuedLocks::Acquirer::ReleaseLock
229
253
  end
230
254
  # rubocop:enable Metrics/MethodLength
231
255
  end
256
+ # rubocop:enable Metrics/ClassLength
232
257
  end
258
+ # rubocop:enable Metrics/ModuleLength
@@ -44,7 +44,7 @@ module RedisQueuedLocks::Acquirer::ReleaseLocksOf
44
44
  # - works in tandem with <config['log_sampling_percent']> and <config['log_sampler']>;
45
45
  # @param log_sampling_percent [Integer]
46
46
  # - the percent of cases that should be logged;
47
- # - take an effect when <config['log_sampling_enalbed']> is true;
47
+ # - take an effect when <config['log_sampling_enabled']> is true;
48
48
  # - works in tandem with <config['log_sampling_enabled']> and <config['log_sampler']> configs;
49
49
  # @param log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
50
50
  # - percent-based log sampler that decides should be RQL case logged or not;
@@ -65,7 +65,7 @@ module RedisQueuedLocks::Acquirer::ReleaseLocksOf
65
65
  # - works in tandem with <config['instr_sampling_percent']> and <config['instr_sampler']>;
66
66
  # @param instr_sampling_percent [Integer]
67
67
  # - the percent of cases that should be instrumented;
68
- # - take an effect when <config['instr_sampling_enalbed']> is true;
68
+ # - take an effect when <config['instr_sampling_enabled']> is true;
69
69
  # - works in tandem with <config['instr_sampling_enabled']>
70
70
  # and <config['instr_sampler']> configs;
71
71
  # @param instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
@@ -93,7 +93,7 @@ module RedisQueuedLocks::Acquirer::ReleaseLocksOf
93
93
  #
94
94
  # @api private
95
95
  # @since 1.14.0
96
- # @version 1.20.0
96
+ # @version 1.21.0
97
97
  # rubocop:disable Metrics/MethodLength
98
98
  def release_locks_of(
99
99
  refused_host_id,
@@ -114,6 +114,22 @@ module RedisQueuedLocks::Acquirer::ReleaseLocksOf
114
114
  instr_sampler,
115
115
  instr_sample_this
116
116
  )
117
+ # NOTE: (arguments) the same ranges as the config keys: zero/negative sizes fail SCAN/ZSCAN
118
+ # (`COUNT 0`) and the batching (`each_slice(0)`);
119
+ if !lock_scan_size.is_a?(::Integer) || lock_scan_size <= 0
120
+ raise(
121
+ RedisQueuedLocks::ArgumentError,
122
+ "`:lock_scan_size` argument should be a positive Integer, got #{lock_scan_size.inspect}."
123
+ )
124
+ end
125
+ if !queue_scan_size.is_a?(::Integer) || queue_scan_size <= 0
126
+ raise(
127
+ RedisQueuedLocks::ArgumentError,
128
+ "`:queue_scan_size` argument should be a positive Integer, " \
129
+ "got #{queue_scan_size.inspect}."
130
+ )
131
+ end
132
+
117
133
  rel_start_time = clock_gettime
118
134
 
119
135
  # steep:ignore:start
@@ -134,6 +150,12 @@ module RedisQueuedLocks::Acquirer::ReleaseLocksOf
134
150
  rel_end_time = clock_gettime
135
151
  rel_time = ((rel_end_time - rel_start_time) / 1_000.0).ceil(2)
136
152
 
153
+ log_sampled = RedisQueuedLocks::Logging.should_log?(
154
+ log_sampling_enabled,
155
+ log_sample_this,
156
+ log_sampling_percent,
157
+ log_sampler
158
+ )
137
159
  instr_sampled = RedisQueuedLocks::Instrument.should_instrument?(
138
160
  instr_sampling_enabled,
139
161
  instr_sample_this,
@@ -141,6 +163,18 @@ module RedisQueuedLocks::Acquirer::ReleaseLocksOf
141
163
  instr_sampler
142
164
  )
143
165
 
166
+ run_non_critical do
167
+ logger.debug do
168
+ "[redis_queued_locks.release_locks_of] " \
169
+ "at => #{time_at} " \
170
+ "hst_id => '#{refused_host_id}' " \
171
+ "acq_id => '#{refused_acquirer_id}' " \
172
+ "rel_time => #{rel_time} " \
173
+ "rel_key_cnt => #{result[:rel_key_cnt]} " \
174
+ "tch_queue_cnt => #{result[:tch_queue_cnt]}"
175
+ end
176
+ end if log_sampled
177
+
144
178
  run_non_critical do
145
179
  instrumenter.notify('redis_queued_locks.release_locks_of', {
146
180
  at: time_at,
@@ -148,7 +182,8 @@ module RedisQueuedLocks::Acquirer::ReleaseLocksOf
148
182
  acq_id: refused_acquirer_id,
149
183
  rel_time: rel_time,
150
184
  rel_key_cnt: result[:rel_key_cnt],
151
- tch_queue_cnt: result[:tch_queue_cnt]
185
+ tch_queue_cnt: result[:tch_queue_cnt],
186
+ instrument: instrument
152
187
  })
153
188
  end if instr_sampled
154
189
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  # @api private
4
4
  # @since 1.18.0
5
+ # @version 1.21.0
5
6
  module RedisQueuedLocks::Acquirer::ReleaseReadLock
6
7
  # @since 1.18.0
7
8
  extend RedisQueuedLocks::Utilities
@@ -17,11 +18,11 @@ module RedisQueuedLocks::Acquirer::ReleaseReadLock
17
18
  # The lock name whose read lock should be released.
18
19
  # @param acquirer_id [String]
19
20
  # The read lock acquirer.
20
- # @param instrumenter [#notify]
21
- # See RedisQueuedLocks::Instrument::ActiveSupport for example.
22
21
  # @param logger [::Logger,#debug]
23
22
  # - Logger object used from `configuration` layer (see config['logger']);
24
23
  # - See RedisQueuedLocks::Logging::VoidLogger for example;
24
+ # @param instrumenter [#notify]
25
+ # See RedisQueuedLocks::Instrument::ActiveSupport for example.
25
26
  # @param instrument [NilClass,Any]
26
27
  # - Custom instrumentation data wich will be passed to the instrumenter's payload
27
28
  # with :instrument key;
@@ -52,13 +53,14 @@ module RedisQueuedLocks::Acquirer::ReleaseReadLock
52
53
  #
53
54
  # @api private
54
55
  # @since 1.18.0
56
+ # @version 1.21.0
55
57
  # rubocop:disable Metrics/MethodLength
56
58
  def release_read_lock(
57
59
  redis,
58
60
  lock_name,
59
61
  acquirer_id,
60
- instrumenter,
61
62
  logger,
63
+ instrumenter,
62
64
  instrument,
63
65
  log_sampling_enabled,
64
66
  log_sampling_percent,
@@ -87,6 +89,12 @@ module RedisQueuedLocks::Acquirer::ReleaseReadLock
87
89
  rel_end_time = clock_gettime
88
90
  rel_time = ((rel_end_time - rel_start_time) / 1_000.0).ceil(2)
89
91
 
92
+ log_sampled = RedisQueuedLocks::Logging.should_log?(
93
+ log_sampling_enabled,
94
+ log_sample_this,
95
+ log_sampling_percent,
96
+ log_sampler
97
+ )
90
98
  instr_sampled = RedisQueuedLocks::Instrument.should_instrument?(
91
99
  instr_sampling_enabled,
92
100
  instr_sample_this,
@@ -94,6 +102,17 @@ module RedisQueuedLocks::Acquirer::ReleaseReadLock
94
102
  instr_sampler
95
103
  )
96
104
 
105
+ run_non_critical do
106
+ logger.debug do
107
+ "[redis_queued_locks.explicit_read_lock_release] " \
108
+ "lock_key => '#{lock_key}' " \
109
+ "acq_id => '#{acquirer_id}' " \
110
+ "lock_res => '#{result[:lock]}' " \
111
+ "rel_time => #{rel_time} " \
112
+ "at => #{time_at}"
113
+ end
114
+ end if log_sampled
115
+
97
116
  run_non_critical do
98
117
  instrumenter.notify('redis_queued_locks.explicit_read_lock_release', {
99
118
  lock_key: lock_key,