sidekiq-unique-jobs 4.0.0 → 4.0.7
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.
- checksums.yaml +4 -4
- data/.simplecov +1 -1
- data/.travis.yml +1 -2
- data/Appraisals +1 -1
- data/CHANGELOG.md +44 -1
- data/Gemfile +1 -2
- data/README.md +49 -51
- data/circle.yml +3 -1
- data/gemfiles/sidekiq_2.17.gemfile +7 -5
- data/gemfiles/sidekiq_3.0.gemfile +6 -4
- data/gemfiles/sidekiq_3.1.gemfile +6 -4
- data/gemfiles/sidekiq_3.2.gemfile +6 -4
- data/gemfiles/sidekiq_3.3.gemfile +6 -4
- data/gemfiles/sidekiq_develop.gemfile +6 -4
- data/lib/sidekiq-unique-jobs.rb +3 -6
- data/lib/sidekiq_unique_jobs/config.rb +1 -6
- data/lib/sidekiq_unique_jobs/constants.rb +17 -0
- data/lib/sidekiq_unique_jobs/core_ext.rb +28 -23
- data/lib/sidekiq_unique_jobs/lock.rb +1 -1
- data/lib/sidekiq_unique_jobs/lock/until_and_while_executing.rb +13 -0
- data/lib/sidekiq_unique_jobs/lock/until_executed.rb +17 -3
- data/lib/sidekiq_unique_jobs/lock/until_executing.rb +4 -0
- data/lib/sidekiq_unique_jobs/lock/until_timeout.rb +9 -2
- data/lib/sidekiq_unique_jobs/lock/while_executing.rb +17 -5
- data/lib/sidekiq_unique_jobs/options_with_fallback.rb +14 -5
- data/lib/sidekiq_unique_jobs/server/middleware.rb +3 -40
- data/lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb +29 -2
- data/lib/sidekiq_unique_jobs/testing/sidekiq_overrides.rb +6 -2
- data/lib/sidekiq_unique_jobs/timeout_calculator.rb +42 -0
- data/lib/sidekiq_unique_jobs/unique_args.rb +31 -29
- data/lib/sidekiq_unique_jobs/version.rb +1 -1
- data/redis/synchronize.lua +1 -1
- data/sidekiq-unique-jobs.gemspec +1 -2
- data/spec/{workers/unique_worker.rb → jobs/another_unique_job.rb} +3 -3
- data/spec/{workers/queue_worker.rb → jobs/custom_queue_job.rb} +1 -1
- data/spec/jobs/custom_queue_job_with_filter_method.rb +7 -0
- data/spec/{workers/queue_worker_with_filter_proc.rb → jobs/custom_queue_job_with_filter_proc.rb} +2 -3
- data/spec/jobs/expiring_job.rb +4 -0
- data/spec/{workers → jobs}/inline_worker.rb +1 -1
- data/spec/jobs/just_a_worker.rb +8 -0
- data/spec/jobs/main_job.rb +8 -0
- data/spec/{workers/my_worker.rb → jobs/my_job.rb} +2 -3
- data/spec/jobs/my_unique_job.rb +7 -0
- data/spec/{workers → jobs}/plain_class.rb +0 -0
- data/spec/{workers → jobs}/test_class.rb +0 -0
- data/spec/{workers → jobs}/unique_job_with_filter_method.rb +2 -2
- data/spec/{workers/unique_on_all_queues_worker.rb → jobs/unique_on_all_queues_job.rb} +3 -3
- data/spec/jobs/until_and_while_executing_job.rb +8 -0
- data/spec/{workers/another_unique_worker.rb → jobs/until_executed_job.rb} +6 -2
- data/spec/jobs/until_executing_job.rb +8 -0
- data/spec/jobs/until_global_timeout_job.rb +8 -0
- data/spec/{workers/inline_expiration_worker.rb → jobs/until_timeout_job.rb} +2 -2
- data/spec/{workers/after_unlock_worker.rb → jobs/while_executing_job.rb} +2 -3
- data/spec/lib/sidekiq_unique_jobs/client/middleware_spec.rb +60 -44
- data/spec/lib/sidekiq_unique_jobs/lock/until_and_while_executing_spec.rb +39 -0
- data/spec/lib/sidekiq_unique_jobs/lock/until_executed_spec.rb +40 -0
- data/spec/lib/sidekiq_unique_jobs/lock/while_executing_spec.rb +15 -4
- data/spec/lib/sidekiq_unique_jobs/options_with_fallback_spec.rb +25 -0
- data/spec/lib/sidekiq_unique_jobs/scripts_spec.rb +3 -4
- data/spec/lib/sidekiq_unique_jobs/server/middleware_spec.rb +51 -68
- data/spec/lib/sidekiq_unique_jobs/sidekiq_testing_enabled_spec.rb +75 -79
- data/spec/lib/sidekiq_unique_jobs/sidekiq_unique_ext_spec.rb +2 -2
- data/spec/lib/sidekiq_unique_jobs/{lock/time_calculator_spec.rb → timeout_calculator_spec.rb} +10 -11
- data/spec/lib/sidekiq_unique_jobs/unique_args_spec.rb +28 -45
- data/spec/spec_helper.rb +23 -15
- data/spec/support/unique_macros.rb +20 -1
- metadata +30 -42
- data/lib/sidekiq_unique_jobs/lock/time_calculator.rb +0 -44
- data/spec/workers/after_yield_worker.rb +0 -17
- data/spec/workers/before_yield_worker.rb +0 -9
- data/spec/workers/expiring_worker.rb +0 -4
- data/spec/workers/inline_unlock_order_worker.rb +0 -8
- data/spec/workers/just_a_worker.rb +0 -8
- data/spec/workers/main_job.rb +0 -8
- data/spec/workers/my_unique_worker.rb +0 -8
- data/spec/workers/queue_worker_with_filter_method.rb +0 -7
- data/spec/workers/run_lock_with_retries_worker.rb +0 -12
- data/spec/workers/run_lock_worker.rb +0 -7
- data/spec/workers/while_executing_worker.rb +0 -13
@@ -34,11 +34,15 @@ module Sidekiq
|
|
34
34
|
end
|
35
35
|
jobs.clear
|
36
36
|
end
|
37
|
+
|
38
|
+
def execute_job(worker, args)
|
39
|
+
worker.perform(*args)
|
40
|
+
end unless respond_to?(:execute_job)
|
37
41
|
end
|
38
42
|
|
39
43
|
module Overrides
|
40
44
|
def self.included(base)
|
41
|
-
base.extend
|
45
|
+
base.extend Testing
|
42
46
|
base.class_eval do
|
43
47
|
class << self
|
44
48
|
alias_method :clear_all_orig, :clear_all
|
@@ -47,7 +51,7 @@ module Sidekiq
|
|
47
51
|
end
|
48
52
|
end
|
49
53
|
|
50
|
-
module
|
54
|
+
module Testing
|
51
55
|
def clear_all_ext
|
52
56
|
Sidekiq.redis do |c|
|
53
57
|
unique_keys = c.keys("#{SidekiqUniqueJobs.config.unique_prefix}:*")
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module SidekiqUniqueJobs
|
2
|
+
class TimeoutCalculator
|
3
|
+
def self.for_item(item)
|
4
|
+
new(item)
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(item)
|
8
|
+
@item = item
|
9
|
+
end
|
10
|
+
|
11
|
+
def seconds
|
12
|
+
time_until_scheduled + unique_expiration
|
13
|
+
end
|
14
|
+
|
15
|
+
def time_until_scheduled
|
16
|
+
scheduled = item[AT_KEY]
|
17
|
+
return 0 unless scheduled
|
18
|
+
(Time.at(scheduled) - Time.now.utc).to_i
|
19
|
+
end
|
20
|
+
|
21
|
+
def unique_expiration
|
22
|
+
@unique_expiration ||=
|
23
|
+
(
|
24
|
+
worker_class_unique_expiration ||
|
25
|
+
SidekiqUniqueJobs.config.default_expiration
|
26
|
+
).to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
def worker_class_unique_expiration
|
30
|
+
return unless worker_class.respond_to?(:get_sidekiq_options)
|
31
|
+
worker_class.get_sidekiq_options[UNIQUE_TIMEOUT_KEY]
|
32
|
+
end
|
33
|
+
|
34
|
+
def worker_class
|
35
|
+
@worker_class ||= SidekiqUniqueJobs.worker_class_constantize(item[CLASS_KEY])
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
attr_reader :item
|
41
|
+
end
|
42
|
+
end
|
@@ -1,26 +1,28 @@
|
|
1
|
+
require 'digest'
|
1
2
|
require 'sidekiq_unique_jobs/normalizer'
|
2
3
|
|
3
4
|
module SidekiqUniqueJobs
|
4
5
|
# This class exists to be testable and the entire api should be considered private
|
5
6
|
# rubocop:disable ClassLength
|
6
7
|
class UniqueArgs
|
8
|
+
CLASS_NAME = 'SidekiqUniqueJobs::UniqueArgs'.freeze
|
7
9
|
extend Forwardable
|
8
10
|
include Normalizer
|
9
11
|
|
10
12
|
def_delegators :SidekiqUniqueJobs, :config, :worker_class_constantize
|
11
|
-
def_delegators :
|
13
|
+
def_delegators :Sidekiq, :logger
|
12
14
|
|
13
15
|
def self.digest(item)
|
14
16
|
new(item).unique_digest
|
15
17
|
end
|
16
18
|
|
17
19
|
def initialize(job)
|
18
|
-
Sidekiq::Logging.with_context(
|
20
|
+
Sidekiq::Logging.with_context(CLASS_NAME) do
|
19
21
|
@item = job
|
20
|
-
@worker_class ||= worker_class_constantize(@item[
|
21
|
-
@item[
|
22
|
-
@item[
|
23
|
-
@item[
|
22
|
+
@worker_class ||= worker_class_constantize(@item[CLASS_KEY])
|
23
|
+
@item[UNIQUE_PREFIX_KEY] ||= unique_prefix
|
24
|
+
@item[UNIQUE_ARGS_KEY] ||= unique_args(@item[ARGS_KEY])
|
25
|
+
@item[UNIQUE_DIGEST_KEY] ||= unique_digest
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
@@ -28,22 +30,24 @@ module SidekiqUniqueJobs
|
|
28
30
|
@unique_digest ||= begin
|
29
31
|
digest = Digest::MD5.hexdigest(Sidekiq.dump_json(digestable_hash))
|
30
32
|
digest = "#{unique_prefix}:#{digest}"
|
31
|
-
debug { "#{__method__} : #{digestable_hash} into #{digest}" }
|
33
|
+
logger.debug { "#{__method__} : #{digestable_hash} into #{digest}" }
|
32
34
|
digest
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
36
38
|
def unique_prefix
|
37
39
|
return config.unique_prefix unless sidekiq_worker_class?
|
38
|
-
@worker_class.get_sidekiq_options[
|
40
|
+
@worker_class.get_sidekiq_options[UNIQUE_PREFIX_KEY] || config.unique_prefix
|
39
41
|
end
|
40
42
|
|
41
43
|
def digestable_hash
|
42
|
-
hash = @item.slice(
|
44
|
+
hash = @item.slice(CLASS_KEY, QUEUE_KEY, UNIQUE_ARGS_KEY)
|
43
45
|
|
44
46
|
if unique_on_all_queues?
|
45
|
-
debug
|
46
|
-
|
47
|
+
logger.debug do
|
48
|
+
"uniqueness specified across all queues (deleting queue: #{@item[QUEUE_KEY]} from hash)"
|
49
|
+
end
|
50
|
+
hash.delete(QUEUE_KEY)
|
47
51
|
end
|
48
52
|
hash
|
49
53
|
end
|
@@ -52,7 +56,7 @@ module SidekiqUniqueJobs
|
|
52
56
|
if unique_args_enabled?
|
53
57
|
filtered_args(args)
|
54
58
|
else
|
55
|
-
debug { "#{__method__} : unique arguments disabled" }
|
59
|
+
logger.debug { "#{__method__} : unique arguments disabled" }
|
56
60
|
args
|
57
61
|
end
|
58
62
|
rescue NameError
|
@@ -62,26 +66,19 @@ module SidekiqUniqueJobs
|
|
62
66
|
|
63
67
|
def unique_on_all_queues?
|
64
68
|
return unless sidekiq_worker_class?
|
65
|
-
|
66
|
-
@worker_class.get_sidekiq_options['unique_on_all_queues'.freeze]
|
69
|
+
@item[UNIQUE_ON_ALL_QUEUES_KEY] || @worker_class.get_sidekiq_options[UNIQUE_ON_ALL_QUEUES_KEY]
|
67
70
|
end
|
68
71
|
|
69
72
|
def unique_args_enabled?
|
70
|
-
unique_args_enabled_in_worker? ||
|
71
|
-
config.unique_args_enabled
|
72
|
-
end
|
73
|
-
|
74
|
-
def unique_args_enabled_in_worker?
|
75
73
|
return unless sidekiq_worker_class?
|
76
|
-
|
77
|
-
@worker_class.get_sidekiq_options['unique_args'.freeze]
|
74
|
+
unique_args_method # && !unique_args_method.is_a?(Boolean)
|
78
75
|
end
|
79
76
|
|
80
77
|
def sidekiq_worker_class?
|
81
78
|
if @worker_class.respond_to?(:get_sidekiq_options)
|
82
79
|
true
|
83
80
|
else
|
84
|
-
debug { "#{@worker_class} does not respond to :get_sidekiq_options" }
|
81
|
+
logger.debug { "#{@worker_class} does not respond to :get_sidekiq_options" }
|
85
82
|
nil
|
86
83
|
end
|
87
84
|
end
|
@@ -91,7 +88,7 @@ module SidekiqUniqueJobs
|
|
91
88
|
def filtered_args(args)
|
92
89
|
return args if args.empty?
|
93
90
|
json_args = Normalizer.jsonify(args)
|
94
|
-
debug { "#filtered_args #{args} => #{json_args}" }
|
91
|
+
logger.debug { "#filtered_args #{args} => #{json_args}" }
|
95
92
|
|
96
93
|
case unique_args_method
|
97
94
|
when Proc
|
@@ -99,20 +96,24 @@ module SidekiqUniqueJobs
|
|
99
96
|
when Symbol
|
100
97
|
filter_by_symbol(json_args)
|
101
98
|
else
|
102
|
-
debug { 'arguments not filtered (the combined arguments count towards uniqueness)' }
|
99
|
+
logger.debug { 'arguments not filtered (the combined arguments count towards uniqueness)' }
|
103
100
|
json_args
|
104
101
|
end
|
105
102
|
end
|
106
103
|
|
107
104
|
def filter_by_proc(args)
|
105
|
+
if unique_args_method.nil?
|
106
|
+
warn { "#{__method__} : Proc was nil, returning args as is #{args} -> #{filter_args}" }
|
107
|
+
return args
|
108
|
+
end
|
108
109
|
filter_args = unique_args_method.call(args)
|
109
|
-
debug { "#{__method__} : #{args} -> #{filter_args}" }
|
110
|
+
logger.debug { "#{__method__} : #{args} -> #{filter_args}" }
|
110
111
|
filter_args
|
111
112
|
end
|
112
113
|
|
113
114
|
def filter_by_symbol(args)
|
114
115
|
unless @worker_class.respond_to?(unique_args_method)
|
115
|
-
warn do
|
116
|
+
logger.warn do
|
116
117
|
"#{__method__} : #{unique_args_method}) not defined in #{@worker_class} " \
|
117
118
|
"returning #{args} unchanged"
|
118
119
|
end
|
@@ -120,13 +121,14 @@ module SidekiqUniqueJobs
|
|
120
121
|
end
|
121
122
|
|
122
123
|
filter_args = @worker_class.send(unique_args_method, args)
|
123
|
-
debug { "#{__method__} : #{unique_args_method}(#{args}) => #{filter_args}" }
|
124
|
+
logger.debug { "#{__method__} : #{unique_args_method}(#{args}) => #{filter_args}" }
|
124
125
|
filter_args
|
125
126
|
end
|
126
127
|
|
127
128
|
def unique_args_method
|
128
|
-
@unique_args_method ||=
|
129
|
-
|
129
|
+
@unique_args_method ||= @worker_class.get_sidekiq_options[UNIQUE_ARGS_KEY] if sidekiq_worker_class?
|
130
|
+
@unique_args_method ||= :unique_args if @worker_class.respond_to?(:unique_args)
|
131
|
+
@unique_args_method ||= Sidekiq.default_worker_options.stringify_keys[UNIQUE_ARGS_KEY]
|
130
132
|
end
|
131
133
|
end
|
132
134
|
end
|
data/redis/synchronize.lua
CHANGED
data/sidekiq-unique-jobs.gemspec
CHANGED
@@ -19,7 +19,6 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.add_development_dependency 'rspec', '~> 3.1.0'
|
20
20
|
gem.add_development_dependency 'rake'
|
21
21
|
gem.add_development_dependency 'rspec-sidekiq'
|
22
|
-
gem.add_development_dependency 'activesupport', '>= 3'
|
23
22
|
gem.add_development_dependency 'rubocop'
|
24
|
-
gem.add_development_dependency '
|
23
|
+
gem.add_development_dependency 'timecop'
|
25
24
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
class
|
1
|
+
class AnotherUniqueJob
|
2
2
|
include Sidekiq::Worker
|
3
|
-
sidekiq_options queue: :working, retry: 1, backtrace: 10
|
4
|
-
|
3
|
+
sidekiq_options queue: :working, retry: 1, backtrace: 10,
|
4
|
+
unique: :until_executed
|
5
5
|
|
6
6
|
sidekiq_retries_exhausted do |msg|
|
7
7
|
Sidekiq.logger.warn "Failed #{msg['class']} with #{msg['args']}: #{msg['error_message']}"
|
data/spec/{workers/queue_worker_with_filter_proc.rb → jobs/custom_queue_job_with_filter_proc.rb}
RENAMED
@@ -1,8 +1,7 @@
|
|
1
|
-
class
|
1
|
+
class CustomQueueJobWithFilterProc < CustomQueueJob
|
2
2
|
# slightly contrived example of munging args to the
|
3
3
|
# worker and removing a random bit.
|
4
|
-
sidekiq_options unique:
|
5
|
-
unique_lock: :until_timeout,
|
4
|
+
sidekiq_options unique: :until_timeout,
|
6
5
|
unique_args: (lambda do |*args|
|
7
6
|
options = args.extract_options!
|
8
7
|
options.delete(:random)
|
@@ -1,7 +1,6 @@
|
|
1
|
-
class
|
1
|
+
class MyJob
|
2
2
|
include Sidekiq::Worker
|
3
|
-
sidekiq_options queue: :working, retry: 1, backtrace: 10
|
4
|
-
sidekiq_options unique: false
|
3
|
+
sidekiq_options queue: :working, retry: 1, backtrace: 10, unique: false
|
5
4
|
|
6
5
|
sidekiq_retries_exhausted do |msg|
|
7
6
|
Sidekiq.logger.warn "Failed #{msg['class']} with #{msg['args']}: #{msg['error_message']}"
|
File without changes
|
File without changes
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class UniqueJobWithFilterMethod
|
2
2
|
include Sidekiq::Worker
|
3
|
-
sidekiq_options queue: :customqueue, retry: 1, backtrace: 10
|
4
|
-
|
3
|
+
sidekiq_options queue: :customqueue, retry: 1, backtrace: 10,
|
4
|
+
unique: :while_executing, unique_args: :filtered_args
|
5
5
|
|
6
6
|
sidekiq_retries_exhausted do |msg|
|
7
7
|
Sidekiq.logger.warn "Failed #{msg['class']} with #{msg['args']}: #{msg['error_message']}"
|
@@ -1,7 +1,7 @@
|
|
1
|
-
class
|
1
|
+
class UniqueOnAllQueuesJob
|
2
2
|
include Sidekiq::Worker
|
3
|
-
sidekiq_options queue: :working, retry: 1, backtrace: 10
|
4
|
-
|
3
|
+
sidekiq_options queue: :working, retry: 1, backtrace: 10,
|
4
|
+
unique: :until_executed, unique_on_all_queues: true
|
5
5
|
|
6
6
|
sidekiq_retries_exhausted do |msg|
|
7
7
|
Sidekiq.logger.warn "Failed #{msg['class']} with #{msg['args']}: #{msg['error_message']}"
|
@@ -1,7 +1,7 @@
|
|
1
|
-
class
|
1
|
+
class UntilExecutedJob
|
2
2
|
include Sidekiq::Worker
|
3
3
|
sidekiq_options queue: :working, retry: 1, backtrace: 10
|
4
|
-
sidekiq_options unique:
|
4
|
+
sidekiq_options unique: :until_executed
|
5
5
|
|
6
6
|
sidekiq_retries_exhausted do |msg|
|
7
7
|
Sidekiq.logger.warn "Failed #{msg['class']} with #{msg['args']}: #{msg['error_message']}"
|
@@ -10,4 +10,8 @@ class AnotherUniqueWorker
|
|
10
10
|
def perform(*)
|
11
11
|
# NO-OP
|
12
12
|
end
|
13
|
+
|
14
|
+
def after_unlock
|
15
|
+
fail 'HELL'
|
16
|
+
end
|
13
17
|
end
|
@@ -1,7 +1,6 @@
|
|
1
|
-
class
|
1
|
+
class WhileExecutingJob
|
2
2
|
include Sidekiq::Worker
|
3
|
-
sidekiq_options queue: :working, retry: 1, backtrace: 10
|
4
|
-
sidekiq_options unique: true, unique_lock: :until_executed
|
3
|
+
sidekiq_options queue: :working, retry: 1, backtrace: 10, unique: :while_executing
|
5
4
|
|
6
5
|
sidekiq_retries_exhausted do |msg|
|
7
6
|
Sidekiq.logger.warn "Failed #{msg['class']} with #{msg['args']}: #{msg['error_message']}"
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'celluloid/current'
|
3
2
|
require 'sidekiq/worker'
|
4
3
|
require 'sidekiq-unique-jobs'
|
5
4
|
require 'sidekiq/scheduled'
|
@@ -13,36 +12,50 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
|
|
13
12
|
before do
|
14
13
|
Sidekiq.redis = REDIS
|
15
14
|
Sidekiq.redis(&:flushdb)
|
16
|
-
QueueWorker.sidekiq_options unique: nil, unique_expiration: nil
|
17
15
|
end
|
18
16
|
|
19
17
|
describe 'when a job is already scheduled' do
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
it 'rejects new scheduled jobs with the same argument' do
|
19
|
+
MyUniqueJob.perform_in(3600, 1)
|
20
|
+
expect(MyUniqueJob.perform_in(3600, 1)).to eq(nil)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'will run a job in real time with the same arguments' do
|
24
|
+
WhileExecutingJob.perform_in(3600, 1)
|
25
|
+
expect(WhileExecutingJob.perform_async(1)).not_to eq(nil)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'schedules new jobs when arguments differ' do
|
29
|
+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].each do |x|
|
30
|
+
MainJob.perform_in(x, x)
|
24
31
|
end
|
25
32
|
|
26
|
-
|
27
|
-
|
28
|
-
expect(
|
33
|
+
Sidekiq.redis do |c|
|
34
|
+
count = c.zcount('schedule', -1, Time.now.to_f + 2 * 60)
|
35
|
+
expect(count).to eq(20)
|
29
36
|
end
|
37
|
+
end
|
30
38
|
|
31
|
-
|
32
|
-
|
33
|
-
|
39
|
+
it 'schedules allows jobs to be scheduled ' do
|
40
|
+
class ShitClass
|
41
|
+
def do_it(_arg)
|
42
|
+
# whatever
|
34
43
|
end
|
44
|
+
end
|
35
45
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
46
|
+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].each do |x|
|
47
|
+
ShitClass.delay_for(x, unique: :while_executing).do_it(1)
|
48
|
+
end
|
49
|
+
|
50
|
+
Sidekiq.redis do |c|
|
51
|
+
count = c.zcount('schedule', -1, Time.now.to_f + 2 * 60)
|
52
|
+
expect(count).to eq(20)
|
40
53
|
end
|
41
54
|
end
|
42
55
|
end
|
43
56
|
|
44
57
|
it 'does not push duplicate messages when configured for unique only' do
|
45
|
-
item = { 'class' =>
|
58
|
+
item = { 'class' => MyUniqueJob, 'queue' => 'customqueue', 'args' => [1, 2] }
|
46
59
|
10.times { Sidekiq::Client.push(item) }
|
47
60
|
Sidekiq.redis do |c|
|
48
61
|
expect(c.llen('queue:customqueue')).to eq(1)
|
@@ -50,8 +63,8 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
|
|
50
63
|
end
|
51
64
|
|
52
65
|
it 'does push duplicate messages to different queues' do
|
53
|
-
Sidekiq::Client.push('class' =>
|
54
|
-
Sidekiq::Client.push('class' =>
|
66
|
+
Sidekiq::Client.push('class' => MyUniqueJob, 'queue' => 'customqueue', 'args' => [1, 2])
|
67
|
+
Sidekiq::Client.push('class' => MyUniqueJob, 'queue' => 'customqueue2', 'args' => [1, 2])
|
55
68
|
Sidekiq.redis do |c|
|
56
69
|
expect(c.llen('queue:customqueue')).to eq 1
|
57
70
|
expect(c.llen('queue:customqueue2')).to eq 1
|
@@ -59,14 +72,14 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
|
|
59
72
|
end
|
60
73
|
|
61
74
|
it 'does not queue duplicates when when calling delay' do
|
62
|
-
10.times { PlainClass.delay(
|
75
|
+
10.times { PlainClass.delay(unique: :until_executed, queue: 'customqueue').run(1) }
|
63
76
|
Sidekiq.redis do |c|
|
64
77
|
expect(c.llen('queue:customqueue')).to eq(1)
|
65
78
|
end
|
66
79
|
end
|
67
80
|
|
68
81
|
it 'does not schedule duplicates when calling perform_in' do
|
69
|
-
10.times {
|
82
|
+
10.times { MyUniqueJob.perform_in(60, [1, 2]) }
|
70
83
|
Sidekiq.redis do |c|
|
71
84
|
expect(c.zcount('schedule', -1, Time.now.to_f + 2 * 60))
|
72
85
|
.to eq(1)
|
@@ -74,8 +87,8 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
|
|
74
87
|
end
|
75
88
|
|
76
89
|
it 'enqueues previously scheduled job' do
|
77
|
-
jid =
|
78
|
-
item = { 'class' =>
|
90
|
+
jid = WhileExecutingJob.perform_in(60 * 60, 1, 2)
|
91
|
+
item = { 'class' => WhileExecutingJob, 'queue' => 'customqueue', 'args' => [1, 2], 'jid' => jid }
|
79
92
|
|
80
93
|
# time passes and the job is pulled off the schedule:
|
81
94
|
Sidekiq::Client.push(item)
|
@@ -86,18 +99,20 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
|
|
86
99
|
end
|
87
100
|
|
88
101
|
it 'sets an expiration when provided by sidekiq options' do
|
89
|
-
item = { 'class' =>
|
102
|
+
item = { 'class' => ExpiringJob, 'queue' => 'customqueue', 'args' => [1, 2] }
|
90
103
|
Sidekiq::Client.push(item)
|
91
104
|
|
92
105
|
Sidekiq.redis do |c|
|
93
106
|
expect(c.llen('queue:customqueue')).to eq(1)
|
94
107
|
expect(c.ttl(digest_for(item)))
|
95
|
-
.to eq(
|
108
|
+
.to eq(ExpiringJob.get_sidekiq_options['unique_expiration'])
|
96
109
|
end
|
97
110
|
end
|
98
111
|
|
99
112
|
it 'does push duplicate messages when not configured for unique only' do
|
100
|
-
10.times
|
113
|
+
10.times do
|
114
|
+
Sidekiq::Client.push('class' => CustomQueueJob, 'queue' => 'customqueue', 'args' => [1, 2])
|
115
|
+
end
|
101
116
|
|
102
117
|
Sidekiq.redis do |c|
|
103
118
|
expect(c.llen('queue:customqueue')).to eq(10)
|
@@ -105,16 +120,13 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
|
|
105
120
|
end
|
106
121
|
|
107
122
|
describe 'when unique_args is defined' do
|
108
|
-
before(:all) { SidekiqUniqueJobs.config.unique_args_enabled = true }
|
109
|
-
after(:all) { SidekiqUniqueJobs.config.unique_args_enabled = false }
|
110
|
-
|
111
123
|
it 'does not push duplicate messages based on args filter method' do
|
112
|
-
expect(
|
113
|
-
expect(
|
124
|
+
expect(CustomQueueJobWithFilterMethod).to respond_to(:args_filter)
|
125
|
+
expect(CustomQueueJobWithFilterMethod.get_sidekiq_options['unique_args']).to eq :args_filter
|
114
126
|
|
115
127
|
(0..10).each do |i|
|
116
128
|
Sidekiq::Client.push(
|
117
|
-
'class' =>
|
129
|
+
'class' => CustomQueueJobWithFilterMethod,
|
118
130
|
'queue' => 'customqueue',
|
119
131
|
'args' => [1, i]
|
120
132
|
)
|
@@ -126,11 +138,11 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
|
|
126
138
|
end
|
127
139
|
|
128
140
|
it 'does not push duplicate messages based on args filter proc' do
|
129
|
-
expect(
|
141
|
+
expect(CustomQueueJobWithFilterProc.get_sidekiq_options['unique_args']).to be_a(Proc)
|
130
142
|
|
131
143
|
100.times do
|
132
144
|
Sidekiq::Client.push(
|
133
|
-
'class' =>
|
145
|
+
'class' => CustomQueueJobWithFilterProc,
|
134
146
|
'queue' => 'customqueue',
|
135
147
|
'args' => [1, { random: rand, name: 'foobar' }]
|
136
148
|
)
|
@@ -143,7 +155,7 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
|
|
143
155
|
|
144
156
|
describe 'when unique_on_all_queues is set' do
|
145
157
|
it 'does not push duplicate messages on different queues' do
|
146
|
-
item = { 'class' =>
|
158
|
+
item = { 'class' => UniqueOnAllQueuesJob, 'args' => [1, 2] }
|
147
159
|
Sidekiq::Client.push(item.merge('queue' => 'customqueue'))
|
148
160
|
Sidekiq::Client.push(item.merge('queue' => 'customqueue2'))
|
149
161
|
Sidekiq.redis do |c|
|
@@ -158,9 +170,9 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
|
|
158
170
|
# jobs are set around the same time as the scheduled job itself feel free to improve.
|
159
171
|
it 'expires the digest when a scheduled job is scheduled at' do
|
160
172
|
expected_expires_at =
|
161
|
-
(Time.at(
|
162
|
-
jid =
|
163
|
-
item = { 'class' =>
|
173
|
+
(Time.at(Time.now.to_i + 15 * 60) - Time.now.utc) + SidekiqUniqueJobs.config.default_expiration
|
174
|
+
jid = MyUniqueJob.perform_in(expected_expires_at, 'mike')
|
175
|
+
item = { 'class' => MyUniqueJob,
|
164
176
|
'queue' => 'customqueue',
|
165
177
|
'args' => ['mike'],
|
166
178
|
'at' => expected_expires_at }
|
@@ -172,24 +184,28 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
|
|
172
184
|
|
173
185
|
it 'logs duplicate payload when config turned on' do
|
174
186
|
expect(Sidekiq.logger).to receive(:warn).with(/^payload is not unique/)
|
175
|
-
|
176
|
-
2.times
|
187
|
+
UntilExecutedJob.sidekiq_options log_duplicate_payload: true
|
188
|
+
2.times do
|
189
|
+
Sidekiq::Client.push('class' => UntilExecutedJob, 'queue' => 'customqueue', 'args' => [1, 2])
|
190
|
+
end
|
177
191
|
Sidekiq.redis do |c|
|
178
192
|
expect(c.llen('queue:customqueue')).to eq 1
|
179
193
|
end
|
180
|
-
|
194
|
+
UntilExecutedJob.sidekiq_options log_duplicate_payload: true
|
181
195
|
end
|
182
196
|
|
183
197
|
it 'does not log duplicate payload when config turned off' do
|
184
198
|
expect(Sidekiq.logger).to_not receive(:warn).with(/^payload is not unique/)
|
185
199
|
|
186
|
-
|
200
|
+
UntilExecutedJob.sidekiq_options log_duplicate_payload: false
|
187
201
|
|
188
|
-
2.times
|
202
|
+
2.times do
|
203
|
+
Sidekiq::Client.push('class' => UntilExecutedJob, 'queue' => 'customqueue', 'args' => [1, 2])
|
204
|
+
end
|
189
205
|
Sidekiq.redis do |c|
|
190
206
|
expect(c.llen('queue:customqueue')).to eq 1
|
191
207
|
end
|
192
|
-
|
208
|
+
UntilExecutedJob.sidekiq_options log_duplicate_payload: true
|
193
209
|
end
|
194
210
|
end
|
195
211
|
end
|