sidekiq-unique-jobs 4.0.0 → 4.0.7
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.
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
|