sidekiq 6.0.7 → 6.5.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 might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Changes.md +209 -2
- data/LICENSE +3 -3
- data/README.md +11 -10
- data/bin/sidekiq +8 -3
- data/bin/sidekiqload +70 -66
- data/bin/sidekiqmon +1 -1
- data/lib/generators/sidekiq/job_generator.rb +57 -0
- data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
- data/lib/generators/sidekiq/templates/{worker_spec.rb.erb → job_spec.rb.erb} +1 -1
- data/lib/generators/sidekiq/templates/{worker_test.rb.erb → job_test.rb.erb} +1 -1
- data/lib/sidekiq/api.rb +180 -123
- data/lib/sidekiq/cli.rb +80 -45
- data/lib/sidekiq/client.rb +52 -71
- data/lib/sidekiq/{util.rb → component.rb} +11 -14
- data/lib/sidekiq/delay.rb +2 -0
- data/lib/sidekiq/extensions/action_mailer.rb +3 -2
- data/lib/sidekiq/extensions/active_record.rb +4 -3
- data/lib/sidekiq/extensions/class_methods.rb +5 -4
- data/lib/sidekiq/extensions/generic_proxy.rb +4 -2
- data/lib/sidekiq/fetch.rb +41 -30
- data/lib/sidekiq/job.rb +13 -0
- data/lib/sidekiq/job_logger.rb +16 -28
- data/lib/sidekiq/job_retry.rb +36 -36
- data/lib/sidekiq/job_util.rb +71 -0
- data/lib/sidekiq/launcher.rb +123 -63
- data/lib/sidekiq/logger.rb +11 -20
- data/lib/sidekiq/manager.rb +35 -34
- data/lib/sidekiq/middleware/chain.rb +28 -17
- data/lib/sidekiq/middleware/current_attributes.rb +61 -0
- data/lib/sidekiq/middleware/i18n.rb +6 -4
- data/lib/sidekiq/middleware/modules.rb +19 -0
- data/lib/sidekiq/monitor.rb +1 -1
- data/lib/sidekiq/paginator.rb +8 -8
- data/lib/sidekiq/processor.rb +41 -41
- data/lib/sidekiq/rails.rb +38 -22
- data/lib/sidekiq/redis_client_adapter.rb +154 -0
- data/lib/sidekiq/redis_connection.rb +87 -53
- data/lib/sidekiq/ring_buffer.rb +29 -0
- data/lib/sidekiq/scheduled.rb +60 -24
- data/lib/sidekiq/sd_notify.rb +1 -1
- data/lib/sidekiq/testing/inline.rb +4 -4
- data/lib/sidekiq/testing.rb +39 -40
- data/lib/sidekiq/transaction_aware_client.rb +45 -0
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/action.rb +2 -2
- data/lib/sidekiq/web/application.rb +21 -12
- data/lib/sidekiq/web/csrf_protection.rb +180 -0
- data/lib/sidekiq/web/helpers.rb +40 -34
- data/lib/sidekiq/web/router.rb +5 -2
- data/lib/sidekiq/web.rb +36 -72
- data/lib/sidekiq/worker.rb +136 -16
- data/lib/sidekiq.rb +107 -30
- data/sidekiq.gemspec +11 -4
- data/web/assets/images/apple-touch-icon.png +0 -0
- data/web/assets/javascripts/application.js +113 -65
- data/web/assets/javascripts/dashboard.js +51 -51
- data/web/assets/stylesheets/application-dark.css +64 -43
- data/web/assets/stylesheets/application-rtl.css +0 -4
- data/web/assets/stylesheets/application.css +42 -239
- data/web/locales/ar.yml +8 -2
- data/web/locales/en.yml +4 -1
- data/web/locales/es.yml +18 -2
- data/web/locales/fr.yml +8 -1
- data/web/locales/ja.yml +3 -0
- data/web/locales/lt.yml +1 -1
- data/web/locales/pl.yml +4 -4
- data/web/locales/pt-br.yml +27 -9
- data/web/locales/ru.yml +4 -0
- data/web/views/_footer.erb +1 -1
- data/web/views/_job_info.erb +1 -1
- data/web/views/_poll_link.erb +2 -5
- data/web/views/_summary.erb +7 -7
- data/web/views/busy.erb +51 -20
- data/web/views/dashboard.erb +22 -14
- data/web/views/dead.erb +1 -1
- data/web/views/layout.erb +2 -1
- data/web/views/morgue.erb +6 -6
- data/web/views/queue.erb +11 -11
- data/web/views/queues.erb +4 -4
- data/web/views/retries.erb +7 -7
- data/web/views/retry.erb +1 -1
- data/web/views/scheduled.erb +1 -1
- metadata +29 -51
- data/.circleci/config.yml +0 -60
- data/.github/contributing.md +0 -32
- data/.github/issue_template.md +0 -11
- data/.gitignore +0 -13
- data/.standard.yml +0 -20
- data/3.0-Upgrade.md +0 -70
- data/4.0-Upgrade.md +0 -53
- data/5.0-Upgrade.md +0 -56
- data/6.0-Upgrade.md +0 -72
- data/COMM-LICENSE +0 -97
- data/Ent-2.0-Upgrade.md +0 -37
- data/Ent-Changes.md +0 -256
- data/Gemfile +0 -24
- data/Gemfile.lock +0 -208
- data/Pro-2.0-Upgrade.md +0 -138
- data/Pro-3.0-Upgrade.md +0 -44
- data/Pro-4.0-Upgrade.md +0 -35
- data/Pro-5.0-Upgrade.md +0 -25
- data/Pro-Changes.md +0 -782
- data/Rakefile +0 -10
- data/code_of_conduct.md +0 -50
- data/lib/generators/sidekiq/worker_generator.rb +0 -57
- data/lib/sidekiq/exception_handler.rb +0 -27
data/lib/sidekiq/fetch.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "sidekiq"
|
4
|
+
require "sidekiq/component"
|
4
5
|
|
5
6
|
module Sidekiq
|
6
7
|
class BasicFetch
|
8
|
+
include Sidekiq::Component
|
7
9
|
# We want the fetch operation to timeout every few seconds so the thread
|
8
10
|
# can check if the process is shutting down.
|
9
11
|
TIMEOUT = 2
|
10
12
|
|
11
|
-
UnitOfWork = Struct.new(:queue, :job) {
|
13
|
+
UnitOfWork = Struct.new(:queue, :job, :config) {
|
12
14
|
def acknowledge
|
13
15
|
# nothing to do
|
14
16
|
end
|
@@ -18,15 +20,17 @@ module Sidekiq
|
|
18
20
|
end
|
19
21
|
|
20
22
|
def requeue
|
21
|
-
|
23
|
+
config.redis do |conn|
|
22
24
|
conn.rpush(queue, job)
|
23
25
|
end
|
24
26
|
end
|
25
27
|
}
|
26
28
|
|
27
|
-
def initialize(
|
28
|
-
|
29
|
-
@
|
29
|
+
def initialize(config)
|
30
|
+
raise ArgumentError, "missing queue list" unless config[:queues]
|
31
|
+
@config = config
|
32
|
+
@strictly_ordered_queues = !!@config[:strict]
|
33
|
+
@queues = @config[:queues].map { |q| "queue:#{q}" }
|
30
34
|
if @strictly_ordered_queues
|
31
35
|
@queues.uniq!
|
32
36
|
@queues << TIMEOUT
|
@@ -34,47 +38,54 @@ module Sidekiq
|
|
34
38
|
end
|
35
39
|
|
36
40
|
def retrieve_work
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
# data from the first queue that has pending elements. We
|
44
|
-
# recreate the queue command each time we invoke Redis#brpop
|
45
|
-
# to honor weights and avoid queue starvation.
|
46
|
-
def queues_cmd
|
47
|
-
if @strictly_ordered_queues
|
48
|
-
@queues
|
49
|
-
else
|
50
|
-
queues = @queues.shuffle!.uniq
|
51
|
-
queues << TIMEOUT
|
52
|
-
queues
|
41
|
+
qs = queues_cmd
|
42
|
+
# 4825 Sidekiq Pro with all queues paused will return an
|
43
|
+
# empty set of queues with a trailing TIMEOUT value.
|
44
|
+
if qs.size <= 1
|
45
|
+
sleep(TIMEOUT)
|
46
|
+
return nil
|
53
47
|
end
|
48
|
+
|
49
|
+
queue, job = redis { |conn| conn.brpop(*qs) }
|
50
|
+
UnitOfWork.new(queue, job, config) if queue
|
54
51
|
end
|
55
52
|
|
56
|
-
|
57
|
-
# an instance method will make it async to the Fetcher actor
|
58
|
-
def self.bulk_requeue(inprogress, options)
|
53
|
+
def bulk_requeue(inprogress, options)
|
59
54
|
return if inprogress.empty?
|
60
55
|
|
61
|
-
|
56
|
+
logger.debug { "Re-queueing terminated jobs" }
|
62
57
|
jobs_to_requeue = {}
|
63
58
|
inprogress.each do |unit_of_work|
|
64
59
|
jobs_to_requeue[unit_of_work.queue] ||= []
|
65
60
|
jobs_to_requeue[unit_of_work.queue] << unit_of_work.job
|
66
61
|
end
|
67
62
|
|
68
|
-
|
69
|
-
conn.pipelined do
|
63
|
+
redis do |conn|
|
64
|
+
conn.pipelined do |pipeline|
|
70
65
|
jobs_to_requeue.each do |queue, jobs|
|
71
|
-
|
66
|
+
pipeline.rpush(queue, jobs)
|
72
67
|
end
|
73
68
|
end
|
74
69
|
end
|
75
|
-
|
70
|
+
logger.info("Pushed #{inprogress.size} jobs back to Redis")
|
76
71
|
rescue => ex
|
77
|
-
|
72
|
+
logger.warn("Failed to requeue #{inprogress.size} jobs: #{ex.message}")
|
73
|
+
end
|
74
|
+
|
75
|
+
# Creating the Redis#brpop command takes into account any
|
76
|
+
# configured queue weights. By default Redis#brpop returns
|
77
|
+
# data from the first queue that has pending elements. We
|
78
|
+
# recreate the queue command each time we invoke Redis#brpop
|
79
|
+
# to honor weights and avoid queue starvation.
|
80
|
+
def queues_cmd
|
81
|
+
if @strictly_ordered_queues
|
82
|
+
@queues
|
83
|
+
else
|
84
|
+
permute = @queues.shuffle
|
85
|
+
permute.uniq!
|
86
|
+
permute << TIMEOUT
|
87
|
+
permute
|
88
|
+
end
|
78
89
|
end
|
79
90
|
end
|
80
91
|
end
|
data/lib/sidekiq/job.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "sidekiq/worker"
|
2
|
+
|
3
|
+
module Sidekiq
|
4
|
+
# Sidekiq::Job is a new alias for Sidekiq::Worker as of Sidekiq 6.3.0.
|
5
|
+
# Use `include Sidekiq::Job` rather than `include Sidekiq::Worker`.
|
6
|
+
#
|
7
|
+
# The term "worker" is too generic and overly confusing, used in several
|
8
|
+
# different contexts meaning different things. Many people call a Sidekiq
|
9
|
+
# process a "worker". Some people call the thread that executes jobs a
|
10
|
+
# "worker". This change brings Sidekiq closer to ActiveJob where your job
|
11
|
+
# classes extend ApplicationJob.
|
12
|
+
Job = Worker
|
13
|
+
end
|
data/lib/sidekiq/job_logger.rb
CHANGED
@@ -12,46 +12,34 @@ module Sidekiq
|
|
12
12
|
|
13
13
|
yield
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
end
|
15
|
+
Sidekiq::Context.add(:elapsed, elapsed(start))
|
16
|
+
@logger.info("done")
|
18
17
|
rescue Exception
|
19
|
-
|
20
|
-
|
21
|
-
end
|
18
|
+
Sidekiq::Context.add(:elapsed, elapsed(start))
|
19
|
+
@logger.info("fail")
|
22
20
|
|
23
21
|
raise
|
24
22
|
end
|
25
23
|
|
26
24
|
def prepare(job_hash, &block)
|
27
|
-
level = job_hash["log_level"]
|
28
|
-
if level
|
29
|
-
@logger.log_at(level) do
|
30
|
-
Sidekiq::Context.with(job_hash_context(job_hash), &block)
|
31
|
-
end
|
32
|
-
else
|
33
|
-
Sidekiq::Context.with(job_hash_context(job_hash), &block)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def job_hash_context(job_hash)
|
38
25
|
# If we're using a wrapper class, like ActiveJob, use the "wrapped"
|
39
26
|
# attribute to expose the underlying thing.
|
40
27
|
h = {
|
41
|
-
class: job_hash["wrapped"] || job_hash["class"],
|
28
|
+
class: job_hash["display_class"] || job_hash["wrapped"] || job_hash["class"],
|
42
29
|
jid: job_hash["jid"]
|
43
30
|
}
|
44
|
-
h[:bid] = job_hash["bid"] if job_hash
|
45
|
-
h[:tags] = job_hash["tags"] if job_hash
|
46
|
-
h
|
47
|
-
end
|
48
|
-
|
49
|
-
def with_elapsed_time_context(start, &block)
|
50
|
-
Sidekiq::Context.with(elapsed_time_context(start), &block)
|
51
|
-
end
|
31
|
+
h[:bid] = job_hash["bid"] if job_hash.has_key?("bid")
|
32
|
+
h[:tags] = job_hash["tags"] if job_hash.has_key?("tags")
|
52
33
|
|
53
|
-
|
54
|
-
|
34
|
+
Thread.current[:sidekiq_context] = h
|
35
|
+
level = job_hash["log_level"]
|
36
|
+
if level
|
37
|
+
@logger.log_at(level, &block)
|
38
|
+
else
|
39
|
+
yield
|
40
|
+
end
|
41
|
+
ensure
|
42
|
+
Thread.current[:sidekiq_context] = nil
|
55
43
|
end
|
56
44
|
|
57
45
|
private
|
data/lib/sidekiq/job_retry.rb
CHANGED
@@ -25,18 +25,19 @@ module Sidekiq
|
|
25
25
|
#
|
26
26
|
# A job looks like:
|
27
27
|
#
|
28
|
-
# { 'class' => '
|
28
|
+
# { 'class' => 'HardJob', 'args' => [1, 2, 'foo'], 'retry' => true }
|
29
29
|
#
|
30
30
|
# The 'retry' option also accepts a number (in place of 'true'):
|
31
31
|
#
|
32
|
-
# { 'class' => '
|
32
|
+
# { 'class' => 'HardJob', 'args' => [1, 2, 'foo'], 'retry' => 5 }
|
33
33
|
#
|
34
34
|
# The job will be retried this number of times before giving up. (If simply
|
35
35
|
# 'true', Sidekiq retries 25 times)
|
36
36
|
#
|
37
|
-
#
|
37
|
+
# Relevant options for job retries:
|
38
38
|
#
|
39
|
-
# * 'queue' - the queue
|
39
|
+
# * 'queue' - the queue for the initial job
|
40
|
+
# * 'retry_queue' - if job retries should be pushed to a different (e.g. lower priority) queue
|
40
41
|
# * 'retry_count' - number of times we've retried so far.
|
41
42
|
# * 'error_message' - the message from the exception
|
42
43
|
# * 'error_class' - the exception class
|
@@ -52,28 +53,31 @@ module Sidekiq
|
|
52
53
|
#
|
53
54
|
# Sidekiq.options[:max_retries] = 7
|
54
55
|
#
|
55
|
-
# or limit the number of retries for a particular
|
56
|
+
# or limit the number of retries for a particular job and send retries to
|
57
|
+
# a low priority queue with:
|
56
58
|
#
|
57
|
-
# class
|
58
|
-
# include Sidekiq::
|
59
|
-
# sidekiq_options :
|
59
|
+
# class MyJob
|
60
|
+
# include Sidekiq::Job
|
61
|
+
# sidekiq_options retry: 10, retry_queue: 'low'
|
60
62
|
# end
|
61
63
|
#
|
62
64
|
class JobRetry
|
63
65
|
class Handled < ::RuntimeError; end
|
66
|
+
|
64
67
|
class Skip < Handled; end
|
65
68
|
|
66
|
-
include Sidekiq::
|
69
|
+
include Sidekiq::Component
|
67
70
|
|
68
71
|
DEFAULT_MAX_RETRY_ATTEMPTS = 25
|
69
72
|
|
70
|
-
def initialize(options
|
71
|
-
@
|
73
|
+
def initialize(options)
|
74
|
+
@config = options
|
75
|
+
@max_retries = @config[:max_retries] || DEFAULT_MAX_RETRY_ATTEMPTS
|
72
76
|
end
|
73
77
|
|
74
78
|
# The global retry handler requires only the barest of data.
|
75
79
|
# We want to be able to retry as much as possible so we don't
|
76
|
-
# require the
|
80
|
+
# require the job to be instantiated.
|
77
81
|
def global(jobstr, queue)
|
78
82
|
yield
|
79
83
|
rescue Handled => ex
|
@@ -100,14 +104,14 @@ module Sidekiq
|
|
100
104
|
end
|
101
105
|
|
102
106
|
# The local retry support means that any errors that occur within
|
103
|
-
# this block can be associated with the given
|
107
|
+
# this block can be associated with the given job instance.
|
104
108
|
# This is required to support the `sidekiq_retries_exhausted` block.
|
105
109
|
#
|
106
110
|
# Note that any exception from the block is wrapped in the Skip
|
107
111
|
# exception so the global block does not reprocess the error. The
|
108
112
|
# Skip exception is unwrapped within Sidekiq::Processor#process before
|
109
113
|
# calling the handle_exception handlers.
|
110
|
-
def local(
|
114
|
+
def local(jobinst, jobstr, queue)
|
111
115
|
yield
|
112
116
|
rescue Handled => ex
|
113
117
|
raise ex
|
@@ -120,11 +124,11 @@ module Sidekiq
|
|
120
124
|
|
121
125
|
msg = Sidekiq.load_json(jobstr)
|
122
126
|
if msg["retry"].nil?
|
123
|
-
msg["retry"] =
|
127
|
+
msg["retry"] = jobinst.class.get_sidekiq_options["retry"]
|
124
128
|
end
|
125
129
|
|
126
130
|
raise e unless msg["retry"]
|
127
|
-
attempt_retry(
|
131
|
+
attempt_retry(jobinst, msg, queue, e)
|
128
132
|
# We've handled this error associated with this job, don't
|
129
133
|
# need to handle it at the global level
|
130
134
|
raise Skip
|
@@ -132,10 +136,10 @@ module Sidekiq
|
|
132
136
|
|
133
137
|
private
|
134
138
|
|
135
|
-
# Note that +
|
136
|
-
# instantiate the
|
139
|
+
# Note that +jobinst+ can be nil here if an error is raised before we can
|
140
|
+
# instantiate the job instance. All access must be guarded and
|
137
141
|
# best effort.
|
138
|
-
def attempt_retry(
|
142
|
+
def attempt_retry(jobinst, msg, queue, exception)
|
139
143
|
max_retry_attempts = retry_attempts_from(msg["retry"], @max_retries)
|
140
144
|
|
141
145
|
msg["queue"] = (msg["retry_queue"] || queue)
|
@@ -167,7 +171,7 @@ module Sidekiq
|
|
167
171
|
end
|
168
172
|
|
169
173
|
if count < max_retry_attempts
|
170
|
-
delay = delay_for(
|
174
|
+
delay = delay_for(jobinst, count, exception)
|
171
175
|
# Logging here can break retries if the logging device raises ENOSPC #3979
|
172
176
|
# logger.debug { "Failure! Retry #{count} in #{delay} seconds" }
|
173
177
|
retry_at = Time.now.to_f + delay
|
@@ -177,13 +181,13 @@ module Sidekiq
|
|
177
181
|
end
|
178
182
|
else
|
179
183
|
# Goodbye dear message, you (re)tried your best I'm sure.
|
180
|
-
retries_exhausted(
|
184
|
+
retries_exhausted(jobinst, msg, exception)
|
181
185
|
end
|
182
186
|
end
|
183
187
|
|
184
|
-
def retries_exhausted(
|
188
|
+
def retries_exhausted(jobinst, msg, exception)
|
185
189
|
begin
|
186
|
-
block =
|
190
|
+
block = jobinst&.sidekiq_retries_exhausted_block
|
187
191
|
block&.call(msg, exception)
|
188
192
|
rescue => e
|
189
193
|
handle_exception(e, {context: "Error calling retries_exhausted", job: msg})
|
@@ -212,23 +216,19 @@ module Sidekiq
|
|
212
216
|
end
|
213
217
|
end
|
214
218
|
|
215
|
-
def delay_for(
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
+
def delay_for(jobinst, count, exception)
|
220
|
+
jitter = rand(10) * (count + 1)
|
221
|
+
if jobinst&.sidekiq_retry_in_block
|
222
|
+
custom_retry_in = retry_in(jobinst, count, exception).to_i
|
223
|
+
return custom_retry_in + jitter if custom_retry_in > 0
|
219
224
|
end
|
220
|
-
|
221
|
-
end
|
222
|
-
|
223
|
-
# delayed_job uses the same basic formula
|
224
|
-
def seconds_to_delay(count)
|
225
|
-
(count**4) + 15 + (rand(30) * (count + 1))
|
225
|
+
(count**4) + 15 + jitter
|
226
226
|
end
|
227
227
|
|
228
|
-
def retry_in(
|
229
|
-
|
228
|
+
def retry_in(jobinst, count, exception)
|
229
|
+
jobinst.sidekiq_retry_in_block.call(count, exception)
|
230
230
|
rescue Exception => e
|
231
|
-
handle_exception(e, {context: "Failure scheduling retry using the defined `sidekiq_retry_in` in #{
|
231
|
+
handle_exception(e, {context: "Failure scheduling retry using the defined `sidekiq_retry_in` in #{jobinst.class.name}, falling back to default"})
|
232
232
|
nil
|
233
233
|
end
|
234
234
|
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require "securerandom"
|
2
|
+
require "time"
|
3
|
+
|
4
|
+
module Sidekiq
|
5
|
+
module JobUtil
|
6
|
+
# These functions encapsulate various job utilities.
|
7
|
+
|
8
|
+
TRANSIENT_ATTRIBUTES = %w[]
|
9
|
+
|
10
|
+
def validate(item)
|
11
|
+
raise(ArgumentError, "Job must be a Hash with 'class' and 'args' keys: `#{item}`") unless item.is_a?(Hash) && item.key?("class") && item.key?("args")
|
12
|
+
raise(ArgumentError, "Job args must be an Array: `#{item}`") unless item["args"].is_a?(Array)
|
13
|
+
raise(ArgumentError, "Job class must be either a Class or String representation of the class name: `#{item}`") unless item["class"].is_a?(Class) || item["class"].is_a?(String)
|
14
|
+
raise(ArgumentError, "Job 'at' must be a Numeric timestamp: `#{item}`") if item.key?("at") && !item["at"].is_a?(Numeric)
|
15
|
+
raise(ArgumentError, "Job tags must be an Array: `#{item}`") if item["tags"] && !item["tags"].is_a?(Array)
|
16
|
+
end
|
17
|
+
|
18
|
+
def verify_json(item)
|
19
|
+
job_class = item["wrapped"] || item["class"]
|
20
|
+
if Sidekiq[:on_complex_arguments] == :raise
|
21
|
+
msg = <<~EOM
|
22
|
+
Job arguments to #{job_class} must be native JSON types, see https://github.com/mperham/sidekiq/wiki/Best-Practices.
|
23
|
+
To disable this error, remove `Sidekiq.strict_args!` from your initializer.
|
24
|
+
EOM
|
25
|
+
raise(ArgumentError, msg) unless json_safe?(item)
|
26
|
+
elsif Sidekiq[:on_complex_arguments] == :warn
|
27
|
+
Sidekiq.logger.warn <<~EOM unless json_safe?(item)
|
28
|
+
Job arguments to #{job_class} do not serialize to JSON safely. This will raise an error in
|
29
|
+
Sidekiq 7.0. See https://github.com/mperham/sidekiq/wiki/Best-Practices or raise an error today
|
30
|
+
by calling `Sidekiq.strict_args!` during Sidekiq initialization.
|
31
|
+
EOM
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def normalize_item(item)
|
36
|
+
validate(item)
|
37
|
+
|
38
|
+
# merge in the default sidekiq_options for the item's class and/or wrapped element
|
39
|
+
# this allows ActiveJobs to control sidekiq_options too.
|
40
|
+
defaults = normalized_hash(item["class"])
|
41
|
+
defaults = defaults.merge(item["wrapped"].get_sidekiq_options) if item["wrapped"].respond_to?(:get_sidekiq_options)
|
42
|
+
item = defaults.merge(item)
|
43
|
+
|
44
|
+
raise(ArgumentError, "Job must include a valid queue name") if item["queue"].nil? || item["queue"] == ""
|
45
|
+
|
46
|
+
# remove job attributes which aren't necessary to persist into Redis
|
47
|
+
TRANSIENT_ATTRIBUTES.each { |key| item.delete(key) }
|
48
|
+
|
49
|
+
item["jid"] ||= SecureRandom.hex(12)
|
50
|
+
item["class"] = item["class"].to_s
|
51
|
+
item["queue"] = item["queue"].to_s
|
52
|
+
item["created_at"] ||= Time.now.to_f
|
53
|
+
item
|
54
|
+
end
|
55
|
+
|
56
|
+
def normalized_hash(item_class)
|
57
|
+
if item_class.is_a?(Class)
|
58
|
+
raise(ArgumentError, "Message must include a Sidekiq::Job class, not class name: #{item_class.ancestors.inspect}") unless item_class.respond_to?(:get_sidekiq_options)
|
59
|
+
item_class.get_sidekiq_options
|
60
|
+
else
|
61
|
+
Sidekiq.default_job_options
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def json_safe?(item)
|
68
|
+
JSON.parse(JSON.dump(item["args"])) == item["args"]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|