sidekiq-unique-jobs 7.1.19 → 7.1.29

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +144 -1
  3. data/README.md +7 -3
  4. data/lib/sidekiq_unique_jobs/batch_delete.rb +1 -0
  5. data/lib/sidekiq_unique_jobs/cli.rb +33 -8
  6. data/lib/sidekiq_unique_jobs/config.rb +5 -0
  7. data/lib/sidekiq_unique_jobs/constants.rb +1 -0
  8. data/lib/sidekiq_unique_jobs/digests.rb +2 -2
  9. data/lib/sidekiq_unique_jobs/exceptions.rb +3 -3
  10. data/lib/sidekiq_unique_jobs/expiring_digests.rb +14 -0
  11. data/lib/sidekiq_unique_jobs/key.rb +13 -8
  12. data/lib/sidekiq_unique_jobs/lock/until_executing.rb +4 -0
  13. data/lib/sidekiq_unique_jobs/lock.rb +18 -1
  14. data/lib/sidekiq_unique_jobs/lock_args.rb +18 -14
  15. data/lib/sidekiq_unique_jobs/lock_config.rb +4 -4
  16. data/lib/sidekiq_unique_jobs/lock_digest.rb +7 -7
  17. data/lib/sidekiq_unique_jobs/lock_timeout.rb +4 -4
  18. data/lib/sidekiq_unique_jobs/lock_ttl.rb +4 -4
  19. data/lib/sidekiq_unique_jobs/locksmith.rb +29 -9
  20. data/lib/sidekiq_unique_jobs/logging.rb +14 -0
  21. data/lib/sidekiq_unique_jobs/lua/lock.lua +15 -9
  22. data/lib/sidekiq_unique_jobs/lua/lock_until_expired.lua +92 -0
  23. data/lib/sidekiq_unique_jobs/lua/reap_orphans.lua +31 -3
  24. data/lib/sidekiq_unique_jobs/lua/unlock.lua +5 -0
  25. data/lib/sidekiq_unique_jobs/middleware/client.rb +2 -0
  26. data/lib/sidekiq_unique_jobs/middleware/server.rb +2 -0
  27. data/lib/sidekiq_unique_jobs/middleware.rb +4 -4
  28. data/lib/sidekiq_unique_jobs/on_conflict/reschedule.rb +3 -3
  29. data/lib/sidekiq_unique_jobs/options_with_fallback.rb +3 -3
  30. data/lib/sidekiq_unique_jobs/orphans/lua_reaper.rb +1 -1
  31. data/lib/sidekiq_unique_jobs/orphans/manager.rb +1 -14
  32. data/lib/sidekiq_unique_jobs/orphans/ruby_reaper.rb +50 -4
  33. data/lib/sidekiq_unique_jobs/sidekiq_unique_jobs.rb +10 -0
  34. data/lib/sidekiq_unique_jobs/sidekiq_worker_methods.rb +33 -24
  35. data/lib/sidekiq_unique_jobs/testing.rb +31 -13
  36. data/lib/sidekiq_unique_jobs/timer_task.rb +19 -77
  37. data/lib/sidekiq_unique_jobs/version.rb +1 -1
  38. data/lib/sidekiq_unique_jobs/web/helpers.rb +10 -0
  39. data/lib/sidekiq_unique_jobs/web.rb +22 -3
  40. data/lib/sidekiq_unique_jobs.rb +1 -0
  41. data/lib/tasks/changelog.rake +1 -1
  42. metadata +21 -5
@@ -5,50 +5,55 @@ module SidekiqUniqueJobs
5
5
  #
6
6
  # @author Mikael Henriksson <mikael@mhenrixon.com>
7
7
  module SidekiqWorkerMethods
8
+ #
9
+ # @!attribute [r] job_class
10
+ # @return [Sidekiq::Worker] The Sidekiq::Worker implementation
11
+ attr_reader :job_class
12
+
8
13
  # Avoids duplicating worker_class.respond_to? in multiple places
9
14
  # @return [true, false]
10
- def worker_method_defined?(method_sym)
11
- worker_class.respond_to?(method_sym)
15
+ def job_method_defined?(method_sym)
16
+ job_class.respond_to?(method_sym)
12
17
  end
13
18
 
14
19
  # Wraps #get_sidekiq_options to always work with a hash
15
20
  # @return [Hash] of the worker class sidekiq options
16
- def worker_options
17
- return {} unless sidekiq_worker_class?
21
+ def job_options
22
+ return {} unless sidekiq_job_class?
18
23
 
19
- worker_class.get_sidekiq_options.deep_stringify_keys
24
+ job_class.get_sidekiq_options.deep_stringify_keys
20
25
  end
21
26
 
22
27
  # Tests that the
23
- # @return [true] if worker_class responds to get_sidekiq_options
24
- # @return [false] if worker_class does not respond to get_sidekiq_options
25
- def sidekiq_worker_class?
26
- worker_method_defined?(:get_sidekiq_options)
28
+ # @return [true] if job_class responds to get_sidekiq_options
29
+ # @return [false] if job_class does not respond to get_sidekiq_options
30
+ def sidekiq_job_class?
31
+ job_method_defined?(:get_sidekiq_options)
27
32
  end
28
33
 
29
- # The Sidekiq::Worker implementation
30
- # @return [Sidekiq::Worker]
31
- def worker_class
32
- @_worker_class ||= worker_class_constantize # rubocop:disable Naming/MemoizedInstanceVariableName
34
+ def job_class=(obj)
35
+ # this is what was originally passed in, it can be an instance or a class depending on sidekiq version
36
+ @original_job_class = obj
37
+ @job_class = job_class_constantize(obj)
33
38
  end
34
39
 
35
40
  # The hook to call after a successful unlock
36
41
  # @return [Proc]
37
42
  def after_unlock_hook # rubocop:disable Metrics/MethodLength
38
43
  lambda do
39
- if @worker_class.respond_to?(:after_unlock)
44
+ if @original_job_class.respond_to?(:after_unlock)
40
45
  # instance method in sidekiq v6
41
- if @worker_class.method(:after_unlock).arity.positive? # arity check to maintain backwards compatibility
42
- @worker_class.after_unlock(item)
46
+ if @original_job_class.method(:after_unlock).arity.positive? # arity check to maintain backwards compatibility
47
+ @original_job_class.after_unlock(item)
43
48
  else
44
- @worker_class.after_unlock
49
+ @original_job_class.after_unlock
45
50
  end
46
- elsif worker_class.respond_to?(:after_unlock)
51
+ elsif job_class.respond_to?(:after_unlock)
47
52
  # class method regardless of sidekiq version
48
- if worker_class.method(:after_unlock).arity.positive? # arity check to maintain backwards compatibility
49
- worker_class.after_unlock(item)
53
+ if job_class.method(:after_unlock).arity.positive? # arity check to maintain backwards compatibility
54
+ job_class.after_unlock(item)
50
55
  else
51
- worker_class.after_unlock
56
+ job_class.after_unlock
52
57
  end
53
58
  end
54
59
  end
@@ -58,7 +63,7 @@ module SidekiqUniqueJobs
58
63
  # failing back to the original argument when the constant can't be found
59
64
  #
60
65
  # @return [Sidekiq::Worker]
61
- def worker_class_constantize(klazz = @worker_class)
66
+ def job_class_constantize(klazz = @job_class)
62
67
  SidekiqUniqueJobs.safe_constantize(klazz)
63
68
  end
64
69
 
@@ -68,8 +73,12 @@ module SidekiqUniqueJobs
68
73
  #
69
74
  # @return [Hash<Symbol, Object>]
70
75
  #
71
- def default_worker_options
72
- Sidekiq.default_worker_options
76
+ def default_job_options
77
+ if Sidekiq.respond_to?(:default_job_options)
78
+ Sidekiq.default_job_options
79
+ else
80
+ Sidekiq.default_worker_options
81
+ end
73
82
  end
74
83
  end
75
84
  end
@@ -71,18 +71,6 @@ module Sidekiq
71
71
 
72
72
  sidekiq_options(old_options)
73
73
  end
74
-
75
- #
76
- # Clears the jobs for this worker and removes all locks
77
- #
78
- def clear
79
- jobs.each do |job|
80
- SidekiqUniqueJobs::Unlockable.unlock(job)
81
- end
82
-
83
- Sidekiq::Queues[queue].clear
84
- jobs.clear
85
- end
86
74
  end
87
75
 
88
76
  #
@@ -102,6 +90,36 @@ module Sidekiq
102
90
  super(options)
103
91
  end
104
92
 
93
+ #
94
+ # Prepends deletion of locks to clear
95
+ #
96
+ module ClassMethods
97
+ #
98
+ # Clears the jobs for this worker and removes all locks
99
+ #
100
+ def clear
101
+ jobs.each do |job|
102
+ SidekiqUniqueJobs::Unlockable.unlock(job)
103
+ end
104
+
105
+ super
106
+ end
107
+ end
108
+ end
109
+
110
+ prepend Overrides
111
+
112
+ #
113
+ # Prepends methods to Sidekiq::Worker
114
+ #
115
+ module ClassMethods
116
+ prepend Overrides::ClassMethods
117
+ end
118
+
119
+ #
120
+ # Prepends singleton methods to Sidekiq::Worker
121
+ #
122
+ module SignletonOverrides
105
123
  #
106
124
  # Clears all jobs for this worker and removes all locks
107
125
  #
@@ -112,6 +130,6 @@ module Sidekiq
112
130
  end
113
131
  end
114
132
 
115
- prepend Overrides
133
+ singleton_class.prepend SignletonOverrides
116
134
  end
117
135
  end
@@ -26,9 +26,7 @@ module SidekiqUniqueJobs
26
26
  # Should the task experience an unrecoverable crash only the task thread will
27
27
  # crash. This makes the `TimerTask` very fault tolerant. Additionally, the
28
28
  # `TimerTask` thread can respond to the success or failure of the task,
29
- # performing logging or ancillary operations. `TimerTask` can also be
30
- # configured with a timeout value allowing it to kill a task that runs too
31
- # long.
29
+ # performing logging or ancillary operations.
32
30
  #
33
31
  # One other advantage of `TimerTask` is that it forces the business logic to
34
32
  # be completely decoupled from the concurrency logic. The business logic can
@@ -49,9 +47,7 @@ module SidekiqUniqueJobs
49
47
  # {http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html
50
48
  # Observable} module. On execution the `TimerTask` will notify the observers
51
49
  # with three arguments: time of execution, the result of the block (or nil on
52
- # failure), and any raised exceptions (or nil on success). If the timeout
53
- # interval is exceeded the observer will receive a `Concurrent::TimeoutError`
54
- # object as the third argument.
50
+ # failure), and any raised exceptions (or nil on success).
55
51
  #
56
52
  # @!macro copy_options
57
53
  #
@@ -60,20 +56,18 @@ module SidekiqUniqueJobs
60
56
  # task.execute
61
57
  #
62
58
  # task.execution_interval #=> 60 (default)
63
- # task.timeout_interval #=> 30 (default)
64
59
  #
65
60
  # # wait 60 seconds...
66
61
  # #=> 'Boom!'
67
62
  #
68
63
  # task.shutdown #=> true
69
64
  #
70
- # @example Configuring `:execution_interval` and `:timeout_interval`
71
- # task = Concurrent::TimerTask.new(execution_interval: 5, timeout_interval: 5) do
65
+ # @example Configuring `:execution_interval`
66
+ # task = Concurrent::TimerTask.new(execution_interval: 5) do
72
67
  # puts 'Boom!'
73
68
  # end
74
69
  #
75
70
  # task.execution_interval #=> 5
76
- # task.timeout_interval #=> 5
77
71
  #
78
72
  # @example Immediate execution with `:run_now`
79
73
  # task = Concurrent::TimerTask.new(run_now: true){ puts 'Boom!' }
@@ -116,15 +110,13 @@ module SidekiqUniqueJobs
116
110
  # def update(time, result, ex)
117
111
  # if result
118
112
  # print "(#{time}) Execution successfully returned #{result}\n"
119
- # elsif ex.is_a?(Concurrent::TimeoutError)
120
- # print "(#{time}) Execution timed out\n"
121
113
  # else
122
114
  # print "(#{time}) Execution failed with error #{ex}\n"
123
115
  # end
124
116
  # end
125
117
  # end
126
118
  #
127
- # task = Concurrent::TimerTask.new(execution_interval: 1, timeout_interval: 1){ 42 }
119
+ # task = Concurrent::TimerTask.new(execution_interval: 1){ 42 }
128
120
  # task.add_observer(TaskObserver.new)
129
121
  # task.execute
130
122
  # sleep 4
@@ -134,7 +126,7 @@ module SidekiqUniqueJobs
134
126
  # #=> (2013-10-13 19:09:00 -0400) Execution successfully returned 42
135
127
  # task.shutdown
136
128
  #
137
- # task = Concurrent::TimerTask.new(execution_interval: 1, timeout_interval: 1){ sleep }
129
+ # task = Concurrent::TimerTask.new(execution_interval: 1){ sleep }
138
130
  # task.add_observer(TaskObserver.new)
139
131
  # task.execute
140
132
  #
@@ -154,7 +146,7 @@ module SidekiqUniqueJobs
154
146
  #
155
147
  # @see http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html
156
148
  # @see http://docs.oracle.com/javase/7/docs/api/java/util/TimerTask.html
157
- class TimerTask < Concurrent::RubyExecutorService # rubocop:disable Metrics/ClassLength
149
+ class TimerTask < Concurrent::RubyExecutorService
158
150
  include Concurrent::Concern::Dereferenceable
159
151
  include Concurrent::Concern::Observable
160
152
 
@@ -170,8 +162,6 @@ module SidekiqUniqueJobs
170
162
  # @param [Hash] opts the options defining task execution.
171
163
  # @option opts [Integer] :execution_interval number of seconds between
172
164
  # task executions (default: EXECUTION_INTERVAL)
173
- # @option opts [Integer] :timeout_interval number of seconds a task can
174
- # run before it is considered to have failed (default: TIMEOUT_INTERVAL)
175
165
  # @option opts [Boolean] :run_now Whether to run the task immediately
176
166
  # upon instantiation or to wait until the first # execution_interval
177
167
  # has passed (default: false)
@@ -233,7 +223,7 @@ module SidekiqUniqueJobs
233
223
  # task = Concurrent::TimerTask.execute(execution_interval: 10){ print "Hello World\n" }
234
224
  # task.running? #=> true
235
225
  def self.execute(opts = {}, &task)
236
- SidekiqUniqueJobs::TimerTask.new(opts, &task).execute
226
+ TimerTask.new(opts, &task).execute
237
227
  end
238
228
 
239
229
  # @!attribute [rw] execution_interval
@@ -252,22 +242,6 @@ module SidekiqUniqueJobs
252
242
  synchronize { @execution_interval = value }
253
243
  end
254
244
 
255
- # @!attribute [rw] timeout_interval
256
- # @return [Fixnum] Number of seconds the task can run before it is
257
- # considered to have failed.
258
- def timeout_interval
259
- synchronize { @timeout_interval }
260
- end
261
-
262
- # @!attribute [rw] timeout_interval
263
- # @return [Fixnum] Number of seconds the task can run before it is
264
- # considered to have failed.
265
- def timeout_interval=(value)
266
- raise ArgumentError, "must be greater than zero" if (value = value.to_f) <= 0.0
267
-
268
- synchronize { @timeout_interval = value }
269
- end
270
-
271
245
  private :post, :<<
272
246
 
273
247
  private
@@ -276,12 +250,13 @@ module SidekiqUniqueJobs
276
250
  set_deref_options(opts)
277
251
 
278
252
  self.execution_interval = opts[:execution] || opts[:execution_interval] || EXECUTION_INTERVAL
279
- self.timeout_interval = opts[:timeout] || opts[:timeout_interval] || TIMEOUT_INTERVAL
280
- @run_now = opts[:now] || opts[:run_now]
281
- @executor = Concurrent::RubySingleThreadExecutor.new
282
- @running = Concurrent::AtomicBoolean.new(false)
283
- @task = task
284
- @value = nil
253
+ if opts[:timeout] || opts[:timeout_interval]
254
+ warn "TimeTask timeouts are now ignored as these were not able to be implemented correctly"
255
+ end
256
+ @run_now = opts[:now] || opts[:run_now]
257
+ @executor = Concurrent::SafeTaskExecutor.new(task)
258
+ @running = Concurrent::AtomicBoolean.new(false)
259
+ @value = nil
285
260
 
286
261
  self.observers = Concurrent::Collection::CopyOnNotifyObserverSet.new
287
262
  end
@@ -306,52 +281,19 @@ module SidekiqUniqueJobs
306
281
  end
307
282
 
308
283
  # @!visibility private
309
- def execute_task(completion) # rubocop:disable Metrics/MethodLength
284
+ def execute_task(completion)
310
285
  return nil unless @running.true?
311
286
 
312
- timeout_task = -> { timeout_task(completion) }
313
-
314
- Concurrent::ScheduledTask.execute(
315
- timeout_interval,
316
- args: [completion],
317
- &timeout_task
318
- )
319
- @thread_completed = Concurrent::Event.new
320
-
321
- @value = @reason = nil
322
- @executor.post do
323
- @value = @task.call(self)
324
- rescue Exception => ex # rubocop:disable Lint/RescueException
325
- @reason = ex
326
- ensure
327
- @thread_completed.set
328
- end
329
-
330
- @thread_completed.wait
331
-
287
+ _success, value, reason = @executor.execute(self)
332
288
  if completion.try?
289
+ self.value = value
333
290
  schedule_next_task
334
291
  time = Time.now
335
292
  observers.notify_observers do
336
- [time, value, @reason]
293
+ [time, self.value, reason]
337
294
  end
338
295
  end
339
296
  nil
340
297
  end
341
-
342
- # @!visibility private
343
- def timeout_task(completion)
344
- return unless @running.true?
345
- return unless completion.try?
346
-
347
- @executor.kill
348
- @executor.wait_for_termination
349
- @executor = Concurrent::RubySingleThreadExecutor.new
350
-
351
- @thread_completed.set
352
-
353
- schedule_next_task
354
- observers.notify_observers(Time.now, nil, Concurrent::TimeoutError.new)
355
- end
356
298
  end
357
299
  end
@@ -3,5 +3,5 @@
3
3
  module SidekiqUniqueJobs
4
4
  #
5
5
  # @return [String] the current SidekiqUniqueJobs version
6
- VERSION = "7.1.19"
6
+ VERSION = "7.1.29"
7
7
  end
@@ -51,6 +51,16 @@ module SidekiqUniqueJobs
51
51
  @digests ||= SidekiqUniqueJobs::Digests.new
52
52
  end
53
53
 
54
+ #
55
+ # The collection of digests
56
+ #
57
+ #
58
+ # @return [SidekiqUniqueJobs::ExpiringDigests] the sorted set with expiring digests
59
+ #
60
+ def expiring_digests
61
+ @expiring_digests ||= SidekiqUniqueJobs::ExpiringDigests.new
62
+ end
63
+
54
64
  #
55
65
  # The collection of changelog entries
56
66
  #
@@ -8,7 +8,7 @@ module SidekiqUniqueJobs
8
8
  #
9
9
  # @author Mikael Henriksson <mikael@mhenrixon.com>
10
10
  module Web
11
- def self.registered(app) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
11
+ def self.registered(app) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
12
12
  app.helpers do
13
13
  include Web::Helpers
14
14
  end
@@ -49,8 +49,25 @@ module SidekiqUniqueJobs
49
49
  erb(unique_template(:locks))
50
50
  end
51
51
 
52
+ app.get "/expiring_locks" do
53
+ @filter = params[:filter] || "*"
54
+ @filter = "*" if @filter == ""
55
+ @count = (params[:count] || 100).to_i
56
+ @current_cursor = params[:cursor]
57
+ @prev_cursor = params[:prev_cursor]
58
+
59
+ @total_size, @next_cursor, @locks = expiring_digests.page(
60
+ cursor: @current_cursor,
61
+ pattern: @filter,
62
+ page_size: @count,
63
+ )
64
+
65
+ erb(unique_template(:locks))
66
+ end
67
+
52
68
  app.get "/locks/delete_all" do
53
69
  digests.delete_by_pattern("*", count: digests.count)
70
+ expiring_digests.delete_by_pattern("*", count: digests.count)
54
71
  redirect_to :locks
55
72
  end
56
73
 
@@ -63,6 +80,7 @@ module SidekiqUniqueJobs
63
80
 
64
81
  app.get "/locks/:digest/delete" do
65
82
  digests.delete_by_digest(params[:digest])
83
+ expiring_digests.delete_by_digest(params[:digest])
66
84
  redirect_to :locks
67
85
  end
68
86
 
@@ -82,8 +100,9 @@ begin
82
100
  require "sidekiq/web" unless defined?(Sidekiq::Web)
83
101
 
84
102
  Sidekiq::Web.register(SidekiqUniqueJobs::Web)
85
- Sidekiq::Web.tabs["Locks"] = "locks"
86
- Sidekiq::Web.tabs["Changelogs"] = "changelogs"
103
+ Sidekiq::Web.tabs["Locks"] = "locks"
104
+ Sidekiq::Web.tabs["Expiring Locks"] = "expiring_locks"
105
+ Sidekiq::Web.tabs["Changelogs"] = "changelogs"
87
106
  Sidekiq::Web.settings.locales << File.join(File.dirname(__FILE__), "locales")
88
107
  rescue NameError, LoadError => ex
89
108
  SidekiqUniqueJobs.logger.error(ex)
@@ -72,6 +72,7 @@ require "sidekiq_unique_jobs/sidekiq_unique_ext"
72
72
  require "sidekiq_unique_jobs/on_conflict"
73
73
  require "sidekiq_unique_jobs/changelog"
74
74
  require "sidekiq_unique_jobs/digests"
75
+ require "sidekiq_unique_jobs/expiring_digests"
75
76
 
76
77
  require "sidekiq_unique_jobs/config"
77
78
  require "sidekiq_unique_jobs/sidekiq_unique_jobs"
@@ -17,7 +17,7 @@ COMMIT_CHANGELOG_CMD = "git commit -a -m 'Update changelog'"
17
17
  desc "Generate a Changelog"
18
18
  task :changelog do
19
19
  sh("git checkout main")
20
- sh(*CHANGELOG_CMD.push(ENV["CHANGELOG_GITHUB_TOKEN"]))
20
+ sh(*CHANGELOG_CMD.push(ENV.fetch("CHANGELOG_GITHUB_TOKEN", nil)))
21
21
  sh(ADD_CHANGELOG_CMD)
22
22
  sh(COMMIT_CHANGELOG_CMD)
23
23
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-unique-jobs
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.1.19
4
+ version: 7.1.29
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikael Henriksson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-09 00:00:00.000000000 Z
11
+ date: 2022-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: brpoplpush-redis_script
@@ -50,6 +50,20 @@ dependencies:
50
50
  - - ">="
51
51
  - !ruby/object:Gem::Version
52
52
  version: 1.0.5
53
+ - !ruby/object:Gem::Dependency
54
+ name: redis
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "<"
58
+ - !ruby/object:Gem::Version
59
+ version: '5.0'
60
+ type: :runtime
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "<"
65
+ - !ruby/object:Gem::Version
66
+ version: '5.0'
53
67
  - !ruby/object:Gem::Dependency
54
68
  name: sidekiq
55
69
  requirement: !ruby/object:Gem::Requirement
@@ -59,7 +73,7 @@ dependencies:
59
73
  version: '5.0'
60
74
  - - "<"
61
75
  - !ruby/object:Gem::Version
62
- version: '8.0'
76
+ version: '7.0'
63
77
  type: :runtime
64
78
  prerelease: false
65
79
  version_requirements: !ruby/object:Gem::Requirement
@@ -69,7 +83,7 @@ dependencies:
69
83
  version: '5.0'
70
84
  - - "<"
71
85
  - !ruby/object:Gem::Version
72
- version: '8.0'
86
+ version: '7.0'
73
87
  - !ruby/object:Gem::Dependency
74
88
  name: thor
75
89
  requirement: !ruby/object:Gem::Requirement
@@ -116,6 +130,7 @@ files:
116
130
  - lib/sidekiq_unique_jobs/deprecation.rb
117
131
  - lib/sidekiq_unique_jobs/digests.rb
118
132
  - lib/sidekiq_unique_jobs/exceptions.rb
133
+ - lib/sidekiq_unique_jobs/expiring_digests.rb
119
134
  - lib/sidekiq_unique_jobs/job.rb
120
135
  - lib/sidekiq_unique_jobs/json.rb
121
136
  - lib/sidekiq_unique_jobs/key.rb
@@ -144,6 +159,7 @@ files:
144
159
  - lib/sidekiq_unique_jobs/lua/delete_job_by_digest.lua
145
160
  - lib/sidekiq_unique_jobs/lua/find_digest_in_queues.lua
146
161
  - lib/sidekiq_unique_jobs/lua/lock.lua
162
+ - lib/sidekiq_unique_jobs/lua/lock_until_expired.lua
147
163
  - lib/sidekiq_unique_jobs/lua/locked.lua
148
164
  - lib/sidekiq_unique_jobs/lua/queue.lua
149
165
  - lib/sidekiq_unique_jobs/lua/reap_orphans.lua
@@ -257,7 +273,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
257
273
  - !ruby/object:Gem::Version
258
274
  version: '0'
259
275
  requirements: []
260
- rubygems_version: 3.3.7
276
+ rubygems_version: 3.3.26
261
277
  signing_key:
262
278
  specification_version: 4
263
279
  summary: Sidekiq middleware that prevents duplicates jobs