sidekiq-unique-jobs 7.0.13 → 7.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sidekiq-unique-jobs might be problematic. Click here for more details.

Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/README.md +92 -25
  4. data/lib/sidekiq_unique_jobs/config.rb +16 -8
  5. data/lib/sidekiq_unique_jobs/constants.rb +44 -45
  6. data/lib/sidekiq_unique_jobs/deprecation.rb +35 -0
  7. data/lib/sidekiq_unique_jobs/exceptions.rb +9 -0
  8. data/lib/sidekiq_unique_jobs/lock/base_lock.rb +56 -51
  9. data/lib/sidekiq_unique_jobs/lock/until_and_while_executing.rb +31 -9
  10. data/lib/sidekiq_unique_jobs/lock/until_executed.rb +17 -5
  11. data/lib/sidekiq_unique_jobs/lock/until_executing.rb +15 -1
  12. data/lib/sidekiq_unique_jobs/lock/until_expired.rb +21 -0
  13. data/lib/sidekiq_unique_jobs/lock/while_executing.rb +12 -7
  14. data/lib/sidekiq_unique_jobs/lock_config.rb +1 -1
  15. data/lib/sidekiq_unique_jobs/lock_ttl.rb +1 -1
  16. data/lib/sidekiq_unique_jobs/locksmith.rb +80 -81
  17. data/lib/sidekiq_unique_jobs/middleware/client.rb +8 -10
  18. data/lib/sidekiq_unique_jobs/middleware/server.rb +2 -0
  19. data/lib/sidekiq_unique_jobs/on_conflict/reschedule.rb +7 -3
  20. data/lib/sidekiq_unique_jobs/options_with_fallback.rb +4 -11
  21. data/lib/sidekiq_unique_jobs/orphans/manager.rb +1 -0
  22. data/lib/sidekiq_unique_jobs/orphans/reaper_resurrector.rb +170 -0
  23. data/lib/sidekiq_unique_jobs/orphans/ruby_reaper.rb +1 -1
  24. data/lib/sidekiq_unique_jobs/redis/sorted_set.rb +1 -1
  25. data/lib/sidekiq_unique_jobs/reflectable.rb +17 -0
  26. data/lib/sidekiq_unique_jobs/reflections.rb +68 -0
  27. data/lib/sidekiq_unique_jobs/script/caller.rb +3 -1
  28. data/lib/sidekiq_unique_jobs/server.rb +2 -1
  29. data/lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb +13 -35
  30. data/lib/sidekiq_unique_jobs/sidekiq_unique_jobs.rb +21 -0
  31. data/lib/sidekiq_unique_jobs/version.rb +1 -1
  32. data/lib/sidekiq_unique_jobs.rb +4 -0
  33. data/lib/tasks/changelog.rake +14 -14
  34. metadata +12 -8
@@ -8,10 +8,24 @@ module SidekiqUniqueJobs
8
8
  #
9
9
  # @author Mikael Henriksson <mikael@mhenrixon.com>
10
10
  class UntilExecuting < BaseLock
11
+ #
12
+ # Locks a sidekiq job
13
+ #
14
+ # @note Will call a conflict strategy if lock can't be achieved.
15
+ #
16
+ # @return [String, nil] the locked jid when properly locked, else nil.
17
+ #
18
+ def lock
19
+ return lock_failed unless (job_id = locksmith.lock)
20
+ return yield job_id if block_given?
21
+
22
+ job_id
23
+ end
24
+
11
25
  # Executes in the Sidekiq server process
12
26
  # @yield to the worker class perform method
13
27
  def execute
14
- unlock_with_callback
28
+ callback_safely if locksmith.unlock
15
29
  yield
16
30
  end
17
31
  end
@@ -8,6 +8,27 @@ module SidekiqUniqueJobs
8
8
  # @author Mikael Henriksson <mikael@mhenrixon.com>
9
9
  #
10
10
  class UntilExpired < UntilExecuted
11
+ #
12
+ # Locks a sidekiq job
13
+ #
14
+ # @note Will call a conflict strategy if lock can't be achieved.
15
+ #
16
+ # @return [String, nil] the locked jid when properly locked, else nil.
17
+ #
18
+ # @yield to the caller when given a block
19
+ #
20
+ def lock
21
+ return lock_failed unless (job_id = locksmith.lock)
22
+ return yield job_id if block_given?
23
+
24
+ job_id
25
+ end
26
+
27
+ # Executes in the Sidekiq server process
28
+ # @yield to the worker class perform method
29
+ def execute(&block)
30
+ locksmith.execute(&block)
31
+ end
11
32
  end
12
33
  end
13
34
  end
@@ -11,7 +11,7 @@ module SidekiqUniqueJobs
11
11
  #
12
12
  # @author Mikael Henriksson <mikael@mhenrixon.com>
13
13
  class WhileExecuting < BaseLock
14
- RUN_SUFFIX = ":RUN"
14
+ RUN_SUFFIX ||= ":RUN"
15
15
 
16
16
  include SidekiqUniqueJobs::OptionsWithFallback
17
17
  include SidekiqUniqueJobs::Logging::Middleware
@@ -29,7 +29,10 @@ module SidekiqUniqueJobs
29
29
  # These locks should only ever be created in the server process.
30
30
  # @return [true] always returns true
31
31
  def lock
32
- true
32
+ job_id = item[JID]
33
+ yield job_id if block_given?
34
+
35
+ job_id
33
36
  end
34
37
 
35
38
  # Executes in the Sidekiq server process.
@@ -37,13 +40,13 @@ module SidekiqUniqueJobs
37
40
  # @yield to the worker class perform method
38
41
  def execute
39
42
  with_logging_context do
40
- server_strategy&.call unless locksmith.lock do
43
+ call_strategy(origin: :server) unless locksmith.execute do
41
44
  yield
42
- callback_safely
45
+ callback_safely if locksmith.unlock
46
+ ensure
47
+ locksmith.unlock
43
48
  end
44
49
  end
45
- ensure
46
- locksmith.unlock!
47
50
  end
48
51
 
49
52
  private
@@ -51,7 +54,9 @@ module SidekiqUniqueJobs
51
54
  # This is safe as the base_lock always creates a new digest
52
55
  # The append there for needs to be done every time
53
56
  def append_unique_key_suffix
54
- item[LOCK_DIGEST] = item[LOCK_DIGEST] + RUN_SUFFIX
57
+ return if (lock_digest = item[LOCK_DIGEST]).end_with?(RUN_SUFFIX)
58
+
59
+ item[LOCK_DIGEST] = lock_digest + RUN_SUFFIX
55
60
  end
56
61
  end
57
62
  end
@@ -82,7 +82,7 @@ module SidekiqUniqueJobs
82
82
  # @return [true,fakse]
83
83
  #
84
84
  def wait_for_lock?
85
- timeout.nil? || timeout.positive?
85
+ timeout && (timeout.zero? || timeout.positive?)
86
86
  end
87
87
 
88
88
  #
@@ -71,7 +71,7 @@ module SidekiqUniqueJobs
71
71
  ttl ||= item[LOCK_EXPIRATION] # TODO: Deprecate at some point
72
72
  ttl ||= worker_options[LOCK_EXPIRATION] # TODO: Deprecate at some point
73
73
  ttl ||= SidekiqUniqueJobs.config.lock_ttl
74
- ttl && (ttl.to_i + time_until_scheduled)
74
+ ttl && ttl.to_i + time_until_scheduled
75
75
  end
76
76
  end
77
77
  end
@@ -13,6 +13,10 @@ module SidekiqUniqueJobs
13
13
  # @!parse include SidekiqUniqueJobs::Logging
14
14
  include SidekiqUniqueJobs::Logging
15
15
 
16
+ # includes "SidekiqUniqueJobs::Reflectable"
17
+ # @!parse include SidekiqUniqueJobs::Reflectable
18
+ include SidekiqUniqueJobs::Reflectable
19
+
16
20
  # includes "SidekiqUniqueJobs::Timing"
17
21
  # @!parse include SidekiqUniqueJobs::Timing
18
22
  include SidekiqUniqueJobs::Timing
@@ -77,7 +81,7 @@ module SidekiqUniqueJobs
77
81
  # Deletes the lock regardless of if it has a pttl set
78
82
  #
79
83
  def delete!
80
- call_script(:delete, key.to_a, [job_id, config.pttl, config.type, config.limit]).positive?
84
+ call_script(:delete, key.to_a, [job_id, config.pttl, config.type, config.limit]).to_i.positive?
81
85
  end
82
86
 
83
87
  #
@@ -85,16 +89,23 @@ module SidekiqUniqueJobs
85
89
  #
86
90
  # @return [String] the Sidekiq job_id that was locked/queued
87
91
  #
88
- def lock(&block)
92
+ def lock(wait: nil)
93
+ method_name = wait ? :primed_async : :primed_sync
89
94
  redis(redis_pool) do |conn|
90
- return lock_async(conn, &block) if block
91
-
92
- lock_sync(conn) do
95
+ lock!(conn, method(method_name), wait) do
93
96
  return job_id
94
97
  end
95
98
  end
96
99
  end
97
100
 
101
+ def execute(&block)
102
+ raise SidekiqUniqueJobs::InvalidArgument, "#execute needs a block" unless block
103
+
104
+ redis(redis_pool) do |conn|
105
+ lock!(conn, method(:primed_async), &block)
106
+ end
107
+ end
108
+
98
109
  #
99
110
  # Removes the lock keys from Redis if locked by the provided jid/token
100
111
  #
@@ -114,11 +125,17 @@ module SidekiqUniqueJobs
114
125
  # @return [String] Sidekiq job_id (jid) if successful
115
126
  #
116
127
  def unlock!(conn = nil)
117
- call_script(:unlock, key.to_a, argv, conn)
128
+ call_script(:unlock, key.to_a, argv, conn) do |unlocked_jid|
129
+ reflect(:debug, :unlocked, item, unlocked_jid) if unlocked_jid == job_id
130
+
131
+ unlocked_jid
132
+ end
118
133
  end
119
134
 
120
135
  # Checks if this instance is considered locked
121
136
  #
137
+ # @param [Sidekiq::RedisConnection, ConnectionPool] conn the redis connection
138
+ #
122
139
  # @return [true, false] true when the :LOCKED hash contains the job_id
123
140
  #
124
141
  def locked?(conn = nil)
@@ -134,7 +151,7 @@ module SidekiqUniqueJobs
134
151
  # @return [String]
135
152
  #
136
153
  def to_s
137
- "Locksmith##{object_id}(digest=#{key} job_id=#{job_id}, locked=#{locked?})"
154
+ "Locksmith##{object_id}(digest=#{key} job_id=#{job_id} locked=#{locked?})"
138
155
  end
139
156
 
140
157
  #
@@ -159,70 +176,71 @@ module SidekiqUniqueJobs
159
176
 
160
177
  attr_reader :redis_pool
161
178
 
162
- def argv
163
- [job_id, config.pttl, config.type, config.limit]
164
- end
165
-
166
- #
167
- # Used for runtime locks that need automatic unlock after yielding
168
- #
169
- # @param [Redis] conn a redis connection
170
179
  #
171
- # @return [nil] when lock was not possible
172
- # @return [Object] whatever the block returns when lock was acquired
180
+ # Used to reduce some duplication from the two methods
173
181
  #
174
- # @yieldparam [String] job_id a Sidekiq JID
182
+ # @param [Sidekiq::RedisConnection, ConnectionPool] conn the redis connection
183
+ # @param [Method] primed_method reference to the method to use for getting a primed token
175
184
  #
176
- def lock_async(conn)
185
+ # @yieldparam [string] job_id the sidekiq JID
186
+ # @yieldreturn [void] whatever the calling block returns
187
+ def lock!(conn, primed_method, wait = nil)
177
188
  return yield job_id if locked?(conn)
178
189
 
179
- enqueue(conn) do
180
- primed_async(conn) do
181
- locked_token = call_script(:lock, key.to_a, argv, conn)
182
- return yield if locked_token == job_id
190
+ enqueue(conn) do |queued_jid|
191
+ reflect(:debug, item, queued_jid)
192
+
193
+ primed_method.call(conn, wait) do |primed_jid|
194
+ reflect(:debug, :primed, item, primed_jid)
195
+
196
+ locked_jid = call_script(:lock, key.to_a, argv, conn)
197
+ if locked_jid
198
+ reflect(:debug, :locked, item, locked_jid)
199
+ return yield job_id
200
+ end
183
201
  end
184
202
  end
185
- ensure
186
- unlock!(conn)
187
203
  end
188
204
 
189
205
  #
190
- # Pops an enqueued token
191
- # @note Used for runtime locks to avoid problems with blocking commands
192
- # in current thread
206
+ # Prepares all the various lock data
193
207
  #
194
208
  # @param [Redis] conn a redis connection
195
209
  #
196
- # @return [nil] when lock was not possible
197
- # @return [Object] whatever the block returns when lock was acquired
210
+ # @return [nil] when redis was already prepared for this lock
211
+ # @return [yield<String>] when successfully enqueued
198
212
  #
199
- def primed_async(conn)
200
- return yield if Concurrent::Promises
201
- .future(conn) { |red_con| pop_queued(red_con) }
202
- .value(add_drift(config.ttl))
213
+ def enqueue(conn)
214
+ queued_jid, elapsed = timed do
215
+ call_script(:queue, key.to_a, argv, conn)
216
+ end
217
+
218
+ return unless queued_jid
219
+ return unless [job_id, "1"].include?(queued_jid)
203
220
 
204
- warn_about_timeout
221
+ validity = config.pttl - elapsed - drift(config.pttl)
222
+ return unless validity >= 0 || config.pttl.zero?
223
+
224
+ write_lock_info(conn)
225
+ yield job_id
205
226
  end
206
227
 
207
228
  #
208
- # Used for non-runtime locks (no block was given)
229
+ # Pops an enqueued token
230
+ # @note Used for runtime locks to avoid problems with blocking commands
231
+ # in current thread
209
232
  #
210
233
  # @param [Redis] conn a redis connection
211
234
  #
212
235
  # @return [nil] when lock was not possible
213
236
  # @return [Object] whatever the block returns when lock was acquired
214
237
  #
215
- # @yieldparam [String] job_id a Sidekiq JID
216
- #
217
- def lock_sync(conn)
218
- return yield if locked?(conn)
238
+ def primed_async(conn, wait = nil, &block)
239
+ primed_jid = Concurrent::Promises
240
+ .future(conn) { |red_con| pop_queued(red_con, wait) }
241
+ .value(add_drift(wait || config.ttl))
219
242
 
220
- enqueue(conn) do
221
- primed_sync(conn) do
222
- locked_token = call_script(:lock, key.to_a, argv, conn)
223
- return yield locked_token if locked_token
224
- end
225
- end
243
+ handle_primed(primed_jid, &block)
226
244
  end
227
245
 
228
246
  #
@@ -234,12 +252,15 @@ module SidekiqUniqueJobs
234
252
  # @return [nil] when lock was not possible
235
253
  # @return [Object] whatever the block returns when lock was acquired
236
254
  #
237
- def primed_sync(conn)
238
- if (popped_jid = pop_queued(conn))
239
- return yield popped_jid
240
- end
255
+ def primed_sync(conn, wait = nil, &block)
256
+ primed_jid = pop_queued(conn, wait)
257
+ handle_primed(primed_jid, &block)
258
+ end
241
259
 
242
- warn_about_timeout
260
+ def handle_primed(primed_jid)
261
+ return yield job_id if [job_id, "1"].include?(primed_jid)
262
+
263
+ reflect(:timeout, item) unless config.wait_for_lock?
243
264
  end
244
265
 
245
266
  #
@@ -249,9 +270,9 @@ module SidekiqUniqueJobs
249
270
  #
250
271
  # @return [String] a previously enqueued token (now taken off the queue)
251
272
  #
252
- def pop_queued(conn)
253
- if config.wait_for_lock?
254
- brpoplpush(conn)
273
+ def pop_queued(conn, wait = nil)
274
+ if wait || config.wait_for_lock?
275
+ brpoplpush(conn, wait)
255
276
  else
256
277
  rpoplpush(conn)
257
278
  end
@@ -260,9 +281,10 @@ module SidekiqUniqueJobs
260
281
  #
261
282
  # @api private
262
283
  #
263
- def brpoplpush(conn)
284
+ def brpoplpush(conn, wait = nil)
285
+ wait ||= config.timeout
264
286
  # passing timeout 0 to brpoplpush causes it to block indefinitely
265
- conn.brpoplpush(key.queued, key.primed, timeout: config.timeout)
287
+ conn.brpoplpush(key.queued, key.primed, timeout: wait)
266
288
  end
267
289
 
268
290
  #
@@ -272,27 +294,6 @@ module SidekiqUniqueJobs
272
294
  conn.rpoplpush(key.queued, key.primed)
273
295
  end
274
296
 
275
- #
276
- # Prepares all the various lock data
277
- #
278
- # @param [Redis] conn a redis connection
279
- #
280
- # @return [nil] when redis was already prepared for this lock
281
- # @return [yield<String>] when successfully enqueued
282
- #
283
- def enqueue(conn)
284
- queued_token, elapsed = timed do
285
- call_script(:queue, key.to_a, argv, conn)
286
- end
287
-
288
- validity = config.pttl - elapsed - drift(config.pttl)
289
-
290
- return unless queued_token && (validity >= 0 || config.pttl.zero?)
291
-
292
- write_lock_info(conn)
293
- yield queued_token
294
- end
295
-
296
297
  #
297
298
  # Writes lock information to redis.
298
299
  # The lock information contains information about worker, queue, limit etc.
@@ -335,10 +336,8 @@ module SidekiqUniqueJobs
335
336
  conn.hexists(key.locked, job_id)
336
337
  end
337
338
 
338
- def warn_about_timeout
339
- return unless config.wait_for_lock?
340
-
341
- log_debug("Timed out after #{config.timeout}s while waiting for primed token (digest: #{key}, job_id: #{job_id})")
339
+ def argv
340
+ [job_id, config.pttl, config.type, config.limit]
342
341
  end
343
342
 
344
343
  def lock_info
@@ -6,7 +6,12 @@ module SidekiqUniqueJobs
6
6
  #
7
7
  # @author Mikael Henriksson <mikael@mhenrixon.com>
8
8
  class Client
9
+ # prepend "SidekiqUniqueJobs::Middleware"
10
+ # @!parse prepends SidekiqUniqueJobs::Middleware
9
11
  prepend SidekiqUniqueJobs::Middleware
12
+ # includes "SidekiqUniqueJobs::Reflectable"
13
+ # @!parse include SidekiqUniqueJobs::Reflectable
14
+ include SidekiqUniqueJobs::Reflectable
10
15
 
11
16
  # Calls this client middleware
12
17
  # Used from Sidekiq.process_single
@@ -25,18 +30,11 @@ module SidekiqUniqueJobs
25
30
  private
26
31
 
27
32
  def lock
28
- if (_token = lock_instance.lock)
29
- yield
30
- else
31
- warn_about_duplicate
33
+ lock_instance.lock do |_locked_jid|
34
+ reflect(:locked, item)
35
+ return yield
32
36
  end
33
37
  end
34
-
35
- def warn_about_duplicate
36
- return unless log_duplicate?
37
-
38
- log_warn "Already locked with another job_id (#{dump_json(item)})"
39
- end
40
38
  end
41
39
  end
42
40
  end
@@ -6,6 +6,8 @@ module SidekiqUniqueJobs
6
6
  #
7
7
  # @author Mikael Henriksson <mikael@mhenrixon.com>
8
8
  class Server
9
+ # prepend "SidekiqUniqueJobs::Middleware"
10
+ # @!parse prepends SidekiqUniqueJobs::Middleware
9
11
  prepend SidekiqUniqueJobs::Middleware
10
12
 
11
13
  #
@@ -9,6 +9,7 @@ module SidekiqUniqueJobs
9
9
  include SidekiqUniqueJobs::SidekiqWorkerMethods
10
10
  include SidekiqUniqueJobs::Logging
11
11
  include SidekiqUniqueJobs::JSON
12
+ include SidekiqUniqueJobs::Reflectable
12
13
 
13
14
  # @param [Hash] item sidekiq job hash
14
15
  def initialize(item, redis_pool = nil)
@@ -20,10 +21,13 @@ module SidekiqUniqueJobs
20
21
  # This will mess up sidekiq stats because a new job is created
21
22
  def call
22
23
  if sidekiq_worker_class?
23
- log_info("Rescheduling #{item[LOCK_DIGEST]}")
24
- worker_class.perform_in(5, *item[ARGS])
24
+ if worker_class.perform_in(5, *item[ARGS])
25
+ reflect(:rescheduled, item)
26
+ else
27
+ reflect(:reschedule_failed, item)
28
+ end
25
29
  else
26
- log_warn("Skip rescheduling of #{item[LOCK_DIGEST]} because #{worker_class} is not a Sidekiq::Worker")
30
+ reflect(:unknown_sidekiq_worker, item)
27
31
  end
28
32
  end
29
33
  end
@@ -29,15 +29,6 @@ module SidekiqUniqueJobs
29
29
  !unique_enabled?
30
30
  end
31
31
 
32
- # Should duplicate payloads be logged?
33
- #
34
- #
35
- # @return [true, false, nil]
36
- #
37
- def log_duplicate?
38
- options[LOG_DUPLICATE] || item[LOG_DUPLICATE]
39
- end
40
-
41
32
  #
42
33
  # A new lock for this Sidekiq Job
43
34
  #
@@ -55,8 +46,10 @@ module SidekiqUniqueJobs
55
46
  # @return [Class]
56
47
  #
57
48
  def lock_class
58
- @lock_class ||= locks.fetch(lock_type.to_sym) do
59
- raise UnknownLock, "No implementation for `lock: :#{lock_type}`"
49
+ @lock_class ||= begin
50
+ locks.fetch(lock_type.to_sym) do
51
+ raise UnknownLock, "No implementation for `lock: :#{lock_type}`"
52
+ end
60
53
  end
61
54
  end
62
55
 
@@ -31,6 +31,7 @@ module SidekiqUniqueJobs
31
31
  with_logging_context do
32
32
  register_reaper_process
33
33
  log_info("Starting Reaper")
34
+
34
35
  task.add_observer(Observer.new)
35
36
  task.execute
36
37
  task
@@ -0,0 +1,170 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqUniqueJobs
4
+ module Orphans
5
+ # Restarts orphan manager if it is considered dead
6
+ module ReaperResurrector
7
+ module_function
8
+
9
+ include SidekiqUniqueJobs::Connection
10
+ include SidekiqUniqueJobs::Logging
11
+
12
+ DRIFT_FACTOR = 0.1
13
+ REAPERS = [:ruby, :lua].freeze
14
+
15
+ #
16
+ # Starts reaper resurrector that watches orphans reaper
17
+ #
18
+ # @return [SidekiqUniqueJobs::TimerTask] the task that was started
19
+ #
20
+ def start
21
+ return if resurrector_disabled?
22
+ return if reaper_disabled?
23
+
24
+ with_logging_context do
25
+ run_task
26
+ end
27
+ end
28
+
29
+ #
30
+ # Runs reaper resurrector task
31
+ #
32
+ # @return [SidekiqUniqueJobs::TimerTask]
33
+ def run_task
34
+ log_info("Starting Reaper Resurrector")
35
+ task.execute
36
+ task
37
+ end
38
+
39
+ #
40
+ # The task that runs the resurrector
41
+ #
42
+ # @return [SidekiqUniqueJobs::TimerTask]
43
+ def task
44
+ SidekiqUniqueJobs::TimerTask.new(timer_task_options) do
45
+ with_logging_context do
46
+ restart_if_dead
47
+ end
48
+ end
49
+ end
50
+
51
+ #
52
+ # Starts new instance of orphan reaper if reaper is considered dead (reaper mutex has not been refreshed lately)
53
+ #
54
+ def restart_if_dead
55
+ return if reaper_registered?
56
+
57
+ log_info("Reaper is considered dead. Starting new reaper instance")
58
+ orphans_manager.start
59
+ end
60
+
61
+ #
62
+ # Returns orphan manager
63
+ #
64
+ # @return [SidekiqUniqueJobs::Orphans::Manager]
65
+ def orphans_manager
66
+ SidekiqUniqueJobs::Orphans::Manager
67
+ end
68
+
69
+ #
70
+ # Checks if resurrector is disabled
71
+ #
72
+ # @see resurrector_enabled?
73
+ #
74
+ # @return [true, false]
75
+ def resurrector_disabled?
76
+ !resurrector_enabled?
77
+ end
78
+
79
+ #
80
+ # Checks if resurrector is enabled
81
+ #
82
+ # @return [true, false]
83
+ def resurrector_enabled?
84
+ SidekiqUniqueJobs.config.reaper_resurrector_enabled
85
+ end
86
+
87
+ #
88
+ # Checks if reaping is disabled
89
+ #
90
+ # @see reaper_enabled?
91
+ #
92
+ # @return [true, false]
93
+ #
94
+ def reaper_disabled?
95
+ !reaper_enabled?
96
+ end
97
+
98
+ #
99
+ # Checks if reaping is enabled
100
+ #
101
+ # @return [true, false]
102
+ #
103
+ def reaper_enabled?
104
+ REAPERS.include?(reaper)
105
+ end
106
+
107
+ #
108
+ # Checks if reaper is registered
109
+ #
110
+ # @return [true, false]
111
+ def reaper_registered?
112
+ redis do |conn|
113
+ conn.get(UNIQUE_REAPER).to_i + drift_reaper_interval > current_timestamp
114
+ end
115
+ end
116
+
117
+ #
118
+ # @see SidekiqUniqueJobs::Config#reaper
119
+ #
120
+ def reaper
121
+ SidekiqUniqueJobs.config.reaper
122
+ end
123
+
124
+ #
125
+ # Arguments passed on to the timer task
126
+ #
127
+ #
128
+ # @return [Hash]
129
+ #
130
+ def timer_task_options
131
+ { run_now: false,
132
+ execution_interval: reaper_resurrector_interval }
133
+ end
134
+
135
+ #
136
+ # A context to use for all log entries
137
+ #
138
+ #
139
+ # @return [Hash] when logger responds to `:with_context`
140
+ # @return [String] when logger does not responds to `:with_context`
141
+ #
142
+ def logging_context
143
+ if logger_context_hash?
144
+ { "uniquejobs" => "reaper-resurrector" }
145
+ else
146
+ "uniquejobs=reaper-resurrector"
147
+ end
148
+ end
149
+
150
+ #
151
+ # @see SidekiqUniqueJobs::Config#reaper_resurrector_interval
152
+ #
153
+ def reaper_resurrector_interval
154
+ SidekiqUniqueJobs.config.reaper_resurrector_interval
155
+ end
156
+
157
+ def reaper_interval
158
+ SidekiqUniqueJobs.config.reaper_interval
159
+ end
160
+
161
+ def drift_reaper_interval
162
+ reaper_interval + (reaper_interval * DRIFT_FACTOR).to_i
163
+ end
164
+
165
+ def current_timestamp
166
+ Time.now.to_i
167
+ end
168
+ end
169
+ end
170
+ end
@@ -182,7 +182,7 @@ module SidekiqUniqueJobs
182
182
  page_size = 50
183
183
 
184
184
  loop do
185
- range_start = (page * page_size) - deleted_size
185
+ range_start = page * page_size - deleted_size
186
186
  range_end = range_start + page_size - 1
187
187
  entries = conn.lrange(queue_key, range_start, range_end)
188
188
  page += 1
@@ -26,7 +26,7 @@ module SidekiqUniqueJobs
26
26
  #
27
27
  # Adds a value to the sorted set
28
28
  #
29
- # @param [Array<Float, String>, String] the values to add
29
+ # @param [Array<Float, String>, String] values the values to add
30
30
  #
31
31
  # @return [Boolean, Integer] <description>
32
32
  #