sidekiq 6.5.12 → 7.3.9
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.
- checksums.yaml +4 -4
- data/Changes.md +340 -20
- data/README.md +43 -35
- data/bin/multi_queue_bench +271 -0
- data/bin/sidekiq +3 -8
- data/bin/sidekiqload +213 -118
- data/bin/sidekiqmon +3 -0
- data/lib/active_job/queue_adapters/sidekiq_adapter.rb +75 -0
- data/lib/generators/sidekiq/job_generator.rb +2 -0
- data/lib/sidekiq/api.rb +243 -162
- data/lib/sidekiq/capsule.rb +132 -0
- data/lib/sidekiq/cli.rb +60 -75
- data/lib/sidekiq/client.rb +87 -38
- data/lib/sidekiq/component.rb +26 -1
- data/lib/sidekiq/config.rb +311 -0
- data/lib/sidekiq/deploy.rb +64 -0
- data/lib/sidekiq/embedded.rb +63 -0
- data/lib/sidekiq/fetch.rb +11 -14
- data/lib/sidekiq/iterable_job.rb +55 -0
- data/lib/sidekiq/job/interrupt_handler.rb +24 -0
- data/lib/sidekiq/job/iterable/active_record_enumerator.rb +53 -0
- data/lib/sidekiq/job/iterable/csv_enumerator.rb +47 -0
- data/lib/sidekiq/job/iterable/enumerators.rb +135 -0
- data/lib/sidekiq/job/iterable.rb +294 -0
- data/lib/sidekiq/job.rb +382 -10
- data/lib/sidekiq/job_logger.rb +8 -7
- data/lib/sidekiq/job_retry.rb +42 -19
- data/lib/sidekiq/job_util.rb +53 -15
- data/lib/sidekiq/launcher.rb +71 -65
- data/lib/sidekiq/logger.rb +2 -27
- data/lib/sidekiq/manager.rb +9 -11
- data/lib/sidekiq/metrics/query.rb +9 -4
- data/lib/sidekiq/metrics/shared.rb +21 -9
- data/lib/sidekiq/metrics/tracking.rb +40 -26
- data/lib/sidekiq/middleware/chain.rb +19 -18
- data/lib/sidekiq/middleware/current_attributes.rb +85 -20
- data/lib/sidekiq/middleware/modules.rb +2 -0
- data/lib/sidekiq/monitor.rb +18 -4
- data/lib/sidekiq/paginator.rb +8 -2
- data/lib/sidekiq/processor.rb +62 -57
- data/lib/sidekiq/rails.rb +27 -10
- data/lib/sidekiq/redis_client_adapter.rb +31 -71
- data/lib/sidekiq/redis_connection.rb +44 -115
- data/lib/sidekiq/ring_buffer.rb +2 -0
- data/lib/sidekiq/scheduled.rb +22 -23
- data/lib/sidekiq/systemd.rb +2 -0
- data/lib/sidekiq/testing.rb +37 -46
- data/lib/sidekiq/transaction_aware_client.rb +11 -5
- data/lib/sidekiq/version.rb +6 -1
- data/lib/sidekiq/web/action.rb +29 -7
- data/lib/sidekiq/web/application.rb +82 -28
- data/lib/sidekiq/web/csrf_protection.rb +10 -7
- data/lib/sidekiq/web/helpers.rb +110 -49
- data/lib/sidekiq/web/router.rb +5 -2
- data/lib/sidekiq/web.rb +70 -17
- data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
- data/lib/sidekiq.rb +78 -274
- data/sidekiq.gemspec +13 -10
- data/web/assets/javascripts/application.js +44 -0
- data/web/assets/javascripts/base-charts.js +106 -0
- data/web/assets/javascripts/dashboard-charts.js +194 -0
- data/web/assets/javascripts/dashboard.js +17 -233
- data/web/assets/javascripts/metrics.js +151 -115
- data/web/assets/stylesheets/application-dark.css +4 -0
- data/web/assets/stylesheets/application-rtl.css +10 -89
- data/web/assets/stylesheets/application.css +56 -296
- data/web/locales/ar.yml +70 -70
- data/web/locales/cs.yml +62 -62
- data/web/locales/da.yml +60 -53
- data/web/locales/de.yml +65 -65
- data/web/locales/el.yml +2 -7
- data/web/locales/en.yml +81 -71
- data/web/locales/es.yml +68 -68
- data/web/locales/fa.yml +65 -65
- data/web/locales/fr.yml +80 -67
- data/web/locales/gd.yml +98 -0
- data/web/locales/he.yml +65 -64
- data/web/locales/hi.yml +59 -59
- data/web/locales/it.yml +85 -54
- data/web/locales/ja.yml +67 -70
- data/web/locales/ko.yml +52 -52
- data/web/locales/lt.yml +66 -66
- data/web/locales/nb.yml +61 -61
- data/web/locales/nl.yml +52 -52
- data/web/locales/pl.yml +45 -45
- data/web/locales/pt-br.yml +78 -69
- data/web/locales/pt.yml +51 -51
- data/web/locales/ru.yml +67 -66
- data/web/locales/sv.yml +53 -53
- data/web/locales/ta.yml +60 -60
- data/web/locales/tr.yml +100 -0
- data/web/locales/uk.yml +85 -61
- data/web/locales/ur.yml +64 -64
- data/web/locales/vi.yml +67 -67
- data/web/locales/zh-cn.yml +20 -19
- data/web/locales/zh-tw.yml +10 -2
- data/web/views/_footer.erb +16 -2
- data/web/views/_job_info.erb +18 -2
- data/web/views/_metrics_period_select.erb +12 -0
- data/web/views/_paging.erb +2 -0
- data/web/views/_poll_link.erb +1 -1
- data/web/views/_summary.erb +7 -7
- data/web/views/busy.erb +46 -35
- data/web/views/dashboard.erb +32 -8
- data/web/views/filtering.erb +6 -0
- data/web/views/layout.erb +6 -6
- data/web/views/metrics.erb +47 -26
- data/web/views/metrics_for_job.erb +43 -71
- data/web/views/morgue.erb +7 -11
- data/web/views/queue.erb +11 -15
- data/web/views/queues.erb +9 -3
- data/web/views/retries.erb +5 -9
- data/web/views/scheduled.erb +12 -13
- metadata +66 -41
- data/lib/sidekiq/delay.rb +0 -43
- data/lib/sidekiq/extensions/action_mailer.rb +0 -48
- data/lib/sidekiq/extensions/active_record.rb +0 -43
- data/lib/sidekiq/extensions/class_methods.rb +0 -43
- data/lib/sidekiq/extensions/generic_proxy.rb +0 -33
- data/lib/sidekiq/metrics/deploy.rb +0 -47
- data/lib/sidekiq/worker.rb +0 -370
- data/web/assets/javascripts/graph.js +0 -16
- /data/{LICENSE → LICENSE.txt} +0 -0
@@ -80,15 +80,6 @@ module Sidekiq
|
|
80
80
|
class Chain
|
81
81
|
include Enumerable
|
82
82
|
|
83
|
-
# A unique instance of the middleware chain is created for
|
84
|
-
# each job executed in order to be thread-safe.
|
85
|
-
# @param copy [Sidekiq::Middleware::Chain] New instance of Chain
|
86
|
-
# @returns nil
|
87
|
-
def initialize_copy(copy)
|
88
|
-
copy.instance_variable_set(:@entries, entries.dup)
|
89
|
-
nil
|
90
|
-
end
|
91
|
-
|
92
83
|
# Iterate through each middleware in the chain
|
93
84
|
def each(&block)
|
94
85
|
entries.each(&block)
|
@@ -105,6 +96,12 @@ module Sidekiq
|
|
105
96
|
@entries ||= []
|
106
97
|
end
|
107
98
|
|
99
|
+
def copy_for(capsule)
|
100
|
+
chain = Sidekiq::Middleware::Chain.new(capsule)
|
101
|
+
chain.instance_variable_set(:@entries, entries.dup)
|
102
|
+
chain
|
103
|
+
end
|
104
|
+
|
108
105
|
# Remove all middleware matching the given Class
|
109
106
|
# @param klass [Class]
|
110
107
|
def remove(klass)
|
@@ -152,6 +149,7 @@ module Sidekiq
|
|
152
149
|
def exists?(klass)
|
153
150
|
any? { |entry| entry.klass == klass }
|
154
151
|
end
|
152
|
+
alias_method :include?, :exists?
|
155
153
|
|
156
154
|
# @return [Boolean] if the chain contains no middleware
|
157
155
|
def empty?
|
@@ -168,23 +166,26 @@ module Sidekiq
|
|
168
166
|
|
169
167
|
# Used by Sidekiq to execute the middleware at runtime
|
170
168
|
# @api private
|
171
|
-
def invoke(*args)
|
169
|
+
def invoke(*args, &block)
|
172
170
|
return yield if empty?
|
173
171
|
|
174
172
|
chain = retrieve
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
173
|
+
traverse(chain, 0, args, &block)
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
|
178
|
+
def traverse(chain, index, args, &block)
|
179
|
+
if index >= chain.size
|
180
|
+
yield
|
181
|
+
else
|
182
|
+
chain[index].call(*args) do
|
183
|
+
traverse(chain, index + 1, args, &block)
|
180
184
|
end
|
181
185
|
end
|
182
|
-
traverse_chain.call
|
183
186
|
end
|
184
187
|
end
|
185
188
|
|
186
|
-
private
|
187
|
-
|
188
189
|
# Represents each link in the middleware chain
|
189
190
|
# @api private
|
190
191
|
class Entry
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/current_attributes"
|
2
4
|
|
3
5
|
module Sidekiq
|
@@ -7,56 +9,119 @@ module Sidekiq
|
|
7
9
|
# This can be useful for multi-tenancy, i18n locale, timezone, any implicit
|
8
10
|
# per-request attribute. See +ActiveSupport::CurrentAttributes+.
|
9
11
|
#
|
12
|
+
# For multiple current attributes, pass an array of current attributes.
|
13
|
+
#
|
10
14
|
# @example
|
11
15
|
#
|
12
16
|
# # in your initializer
|
13
17
|
# require "sidekiq/middleware/current_attributes"
|
14
18
|
# Sidekiq::CurrentAttributes.persist("Myapp::Current")
|
19
|
+
# # or multiple current attributes
|
20
|
+
# Sidekiq::CurrentAttributes.persist(["Myapp::Current", "Myapp::OtherCurrent"])
|
15
21
|
#
|
16
22
|
module CurrentAttributes
|
17
23
|
class Save
|
18
24
|
include Sidekiq::ClientMiddleware
|
19
25
|
|
20
|
-
def initialize(
|
21
|
-
@
|
26
|
+
def initialize(cattrs)
|
27
|
+
@cattrs = cattrs
|
22
28
|
end
|
23
29
|
|
24
30
|
def call(_, job, _, _)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
job
|
29
|
-
|
30
|
-
|
31
|
+
@cattrs.each do |(key, strklass)|
|
32
|
+
if !job.has_key?(key)
|
33
|
+
attrs = strklass.constantize.attributes
|
34
|
+
# Retries can push the job N times, we don't
|
35
|
+
# want retries to reset cattr. #5692, #5090
|
36
|
+
if attrs.any?
|
37
|
+
# Older rails has a bug that `CurrentAttributes#attributes` always returns
|
38
|
+
# the same hash instance. We need to dup it to avoid being accidentally mutated.
|
39
|
+
job[key] = if returns_same_object?
|
40
|
+
attrs.dup
|
41
|
+
else
|
42
|
+
attrs
|
43
|
+
end
|
44
|
+
end
|
31
45
|
end
|
32
46
|
end
|
33
47
|
yield
|
34
48
|
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def returns_same_object?
|
53
|
+
ActiveSupport::VERSION::MAJOR < 8 ||
|
54
|
+
(ActiveSupport::VERSION::MAJOR == 8 && ActiveSupport::VERSION::MINOR == 0)
|
55
|
+
end
|
35
56
|
end
|
36
57
|
|
37
58
|
class Load
|
38
59
|
include Sidekiq::ServerMiddleware
|
39
60
|
|
40
|
-
def initialize(
|
41
|
-
@
|
61
|
+
def initialize(cattrs)
|
62
|
+
@cattrs = cattrs
|
42
63
|
end
|
43
64
|
|
44
65
|
def call(_, job, _, &block)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
66
|
+
klass_attrs = {}
|
67
|
+
|
68
|
+
@cattrs.each do |(key, strklass)|
|
69
|
+
next unless job.has_key?(key)
|
70
|
+
|
71
|
+
klass_attrs[strklass.constantize] = job[key]
|
72
|
+
end
|
73
|
+
|
74
|
+
wrap(klass_attrs.to_a, &block)
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def wrap(klass_attrs, &block)
|
80
|
+
klass, attrs = klass_attrs.shift
|
81
|
+
return block.call unless klass
|
82
|
+
|
83
|
+
retried = false
|
84
|
+
|
85
|
+
begin
|
86
|
+
klass.set(attrs) do
|
87
|
+
wrap(klass_attrs, &block)
|
88
|
+
end
|
89
|
+
rescue NoMethodError
|
90
|
+
raise if retried
|
91
|
+
|
92
|
+
# It is possible that the `CurrentAttributes` definition
|
93
|
+
# was changed before the job started processing.
|
94
|
+
attrs = attrs.select { |attr| klass.respond_to?(attr) }
|
95
|
+
retried = true
|
96
|
+
retry
|
49
97
|
end
|
50
98
|
end
|
51
99
|
end
|
52
100
|
|
53
|
-
|
54
|
-
|
55
|
-
|
101
|
+
class << self
|
102
|
+
def persist(klass_or_array, config = Sidekiq.default_configuration)
|
103
|
+
cattrs = build_cattrs_hash(klass_or_array)
|
104
|
+
|
105
|
+
config.client_middleware.add Save, cattrs
|
106
|
+
config.server_middleware.prepend Load, cattrs
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def build_cattrs_hash(klass_or_array)
|
112
|
+
if klass_or_array.is_a?(Array)
|
113
|
+
{}.tap do |hash|
|
114
|
+
klass_or_array.each_with_index do |klass, index|
|
115
|
+
hash[key_at(index)] = klass.to_s
|
116
|
+
end
|
117
|
+
end
|
118
|
+
else
|
119
|
+
{key_at(0) => klass_or_array.to_s}
|
120
|
+
end
|
56
121
|
end
|
57
|
-
|
58
|
-
|
59
|
-
|
122
|
+
|
123
|
+
def key_at(index)
|
124
|
+
(index == 0) ? "cattr" : "cattr_#{index}"
|
60
125
|
end
|
61
126
|
end
|
62
127
|
end
|
data/lib/sidekiq/monitor.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require "fileutils"
|
4
5
|
require "sidekiq/api"
|
@@ -16,8 +17,6 @@ class Sidekiq::Monitor
|
|
16
17
|
return
|
17
18
|
end
|
18
19
|
send(section)
|
19
|
-
rescue => e
|
20
|
-
abort "Couldn't get status: #{e}"
|
21
20
|
end
|
22
21
|
|
23
22
|
def all
|
@@ -49,10 +48,25 @@ class Sidekiq::Monitor
|
|
49
48
|
def processes
|
50
49
|
puts "---- Processes (#{process_set.size}) ----"
|
51
50
|
process_set.each_with_index do |process, index|
|
51
|
+
# Keep compatibility with legacy versions since we don't want to break sidekiqmon during rolling upgrades or downgrades.
|
52
|
+
#
|
53
|
+
# Before:
|
54
|
+
# ["default", "critical"]
|
55
|
+
#
|
56
|
+
# After:
|
57
|
+
# {"default" => 1, "critical" => 10}
|
58
|
+
queues =
|
59
|
+
if process["weights"]
|
60
|
+
process["weights"].sort_by { |queue| queue[0] }.map { |capsule| capsule.map { |name, weight| (weight > 0) ? "#{name}: #{weight}" : name }.join(", ") }
|
61
|
+
else
|
62
|
+
process["queues"].sort
|
63
|
+
end
|
64
|
+
|
52
65
|
puts "#{process["identity"]} #{tags_for(process)}"
|
53
66
|
puts " Started: #{Time.at(process["started_at"])} (#{time_ago(process["started_at"])})"
|
54
67
|
puts " Threads: #{process["concurrency"]} (#{process["busy"]} busy)"
|
55
|
-
puts " Queues: #{split_multiline(
|
68
|
+
puts " Queues: #{split_multiline(queues, pad: 11)}"
|
69
|
+
puts " Version: #{process["version"] || "Unknown"}" if process["version"] != Sidekiq::VERSION
|
56
70
|
puts "" unless (index + 1) == process_set.size
|
57
71
|
end
|
58
72
|
end
|
@@ -85,7 +99,7 @@ class Sidekiq::Monitor
|
|
85
99
|
pad = opts[:pad] || 0
|
86
100
|
max_length = opts[:max_length] || (80 - pad)
|
87
101
|
out = []
|
88
|
-
line = ""
|
102
|
+
line = +""
|
89
103
|
values.each do |value|
|
90
104
|
if (line.length + value.length) > max_length
|
91
105
|
out << line
|
data/lib/sidekiq/paginator.rb
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
|
3
3
|
module Sidekiq
|
4
4
|
module Paginator
|
5
|
+
TYPE_CACHE = {
|
6
|
+
"dead" => "zset",
|
7
|
+
"retry" => "zset",
|
8
|
+
"schedule" => "zset"
|
9
|
+
}
|
10
|
+
|
5
11
|
def page(key, pageidx = 1, page_size = 25, opts = nil)
|
6
12
|
current_page = (pageidx.to_i < 1) ? 1 : pageidx.to_i
|
7
13
|
pageidx = current_page - 1
|
@@ -19,9 +25,9 @@ module Sidekiq
|
|
19
25
|
total_size, items = conn.multi { |transaction|
|
20
26
|
transaction.zcard(key)
|
21
27
|
if rev
|
22
|
-
transaction.
|
28
|
+
transaction.zrange(key, starting, ending, "REV", "withscores")
|
23
29
|
else
|
24
|
-
transaction.zrange(key, starting, ending, withscores
|
30
|
+
transaction.zrange(key, starting, ending, "withscores")
|
25
31
|
end
|
26
32
|
}
|
27
33
|
[current_page, total_size, items]
|
data/lib/sidekiq/processor.rb
CHANGED
@@ -26,18 +26,18 @@ module Sidekiq
|
|
26
26
|
|
27
27
|
attr_reader :thread
|
28
28
|
attr_reader :job
|
29
|
+
attr_reader :capsule
|
29
30
|
|
30
|
-
def initialize(
|
31
|
+
def initialize(capsule, &block)
|
32
|
+
@config = @capsule = capsule
|
31
33
|
@callback = block
|
32
34
|
@down = false
|
33
35
|
@done = false
|
34
36
|
@job = nil
|
35
37
|
@thread = nil
|
36
|
-
@
|
37
|
-
@
|
38
|
-
@
|
39
|
-
@job_logger = (options[:job_logger] || Sidekiq::JobLogger).new
|
40
|
-
@retrier = Sidekiq::JobRetry.new(options)
|
38
|
+
@reloader = Sidekiq.default_configuration[:reloader]
|
39
|
+
@job_logger = (capsule.config[:job_logger] || Sidekiq::JobLogger).new(capsule.config)
|
40
|
+
@retrier = Sidekiq::JobRetry.new(capsule)
|
41
41
|
end
|
42
42
|
|
43
43
|
def terminate(wait = false)
|
@@ -58,13 +58,21 @@ module Sidekiq
|
|
58
58
|
@thread.value if wait
|
59
59
|
end
|
60
60
|
|
61
|
+
def stopping?
|
62
|
+
@done
|
63
|
+
end
|
64
|
+
|
61
65
|
def start
|
62
|
-
@thread ||= safe_thread("processor", &method(:run))
|
66
|
+
@thread ||= safe_thread("#{config.name}/processor", &method(:run))
|
63
67
|
end
|
64
68
|
|
65
69
|
private unless $TESTING
|
66
70
|
|
67
71
|
def run
|
72
|
+
# By setting this thread-local, Sidekiq.redis will access +Sidekiq::Capsule#redis_pool+
|
73
|
+
# instead of the global pool in +Sidekiq::Config#redis_pool+.
|
74
|
+
Thread.current[:sidekiq_capsule] = @capsule
|
75
|
+
|
68
76
|
process_one until @done
|
69
77
|
@callback.call(self)
|
70
78
|
rescue Sidekiq::Shutdown
|
@@ -80,7 +88,7 @@ module Sidekiq
|
|
80
88
|
end
|
81
89
|
|
82
90
|
def get_one
|
83
|
-
uow =
|
91
|
+
uow = capsule.fetcher.retrieve_work
|
84
92
|
if @down
|
85
93
|
logger.info { "Redis is online, #{::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - @down} sec downtime" }
|
86
94
|
@down = nil
|
@@ -129,11 +137,12 @@ module Sidekiq
|
|
129
137
|
# the Reloader. It handles code loading, db connection management, etc.
|
130
138
|
# Effectively this block denotes a "unit of work" to Rails.
|
131
139
|
@reloader.call do
|
132
|
-
klass =
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
140
|
+
klass = Object.const_get(job_hash["class"])
|
141
|
+
instance = klass.new
|
142
|
+
instance.jid = job_hash["jid"]
|
143
|
+
instance._context = self
|
144
|
+
@retrier.local(instance, jobstr, queue) do
|
145
|
+
yield instance
|
137
146
|
end
|
138
147
|
end
|
139
148
|
end
|
@@ -142,6 +151,11 @@ module Sidekiq
|
|
142
151
|
end
|
143
152
|
end
|
144
153
|
|
154
|
+
IGNORE_SHUTDOWN_INTERRUPTS = {Sidekiq::Shutdown => :never}
|
155
|
+
private_constant :IGNORE_SHUTDOWN_INTERRUPTS
|
156
|
+
ALLOW_SHUTDOWN_INTERRUPTS = {Sidekiq::Shutdown => :immediate}
|
157
|
+
private_constant :ALLOW_SHUTDOWN_INTERRUPTS
|
158
|
+
|
145
159
|
def process(uow)
|
146
160
|
jobstr = uow.job
|
147
161
|
queue = uow.queue_name
|
@@ -153,53 +167,57 @@ module Sidekiq
|
|
153
167
|
rescue => ex
|
154
168
|
handle_exception(ex, {context: "Invalid JSON for job", jobstr: jobstr})
|
155
169
|
now = Time.now.to_f
|
156
|
-
|
170
|
+
redis do |conn|
|
157
171
|
conn.multi do |xa|
|
158
172
|
xa.zadd("dead", now.to_s, jobstr)
|
159
|
-
xa.zremrangebyscore("dead", "-inf", now - config[:dead_timeout_in_seconds])
|
160
|
-
xa.zremrangebyrank("dead", 0, - config[:dead_max_jobs])
|
173
|
+
xa.zremrangebyscore("dead", "-inf", now - @capsule.config[:dead_timeout_in_seconds])
|
174
|
+
xa.zremrangebyrank("dead", 0, - @capsule.config[:dead_max_jobs])
|
161
175
|
end
|
162
176
|
end
|
163
177
|
return uow.acknowledge
|
164
178
|
end
|
165
179
|
|
166
180
|
ack = false
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
181
|
+
Thread.handle_interrupt(IGNORE_SHUTDOWN_INTERRUPTS) do
|
182
|
+
Thread.handle_interrupt(ALLOW_SHUTDOWN_INTERRUPTS) do
|
183
|
+
dispatch(job_hash, queue, jobstr) do |instance|
|
184
|
+
config.server_middleware.invoke(instance, job_hash, queue) do
|
185
|
+
execute_job(instance, job_hash["args"])
|
186
|
+
end
|
171
187
|
end
|
188
|
+
ack = true
|
189
|
+
rescue Sidekiq::Shutdown
|
190
|
+
# Had to force kill this job because it didn't finish
|
191
|
+
# within the timeout. Don't acknowledge the work since
|
192
|
+
# we didn't properly finish it.
|
193
|
+
rescue Sidekiq::JobRetry::Skip => s
|
194
|
+
# Skip means we handled this error elsewhere. We don't
|
195
|
+
# need to log or report the error.
|
196
|
+
ack = true
|
197
|
+
raise s
|
198
|
+
rescue Sidekiq::JobRetry::Handled => h
|
199
|
+
# this is the common case: job raised error and Sidekiq::JobRetry::Handled
|
200
|
+
# signals that we created a retry successfully. We can acknowledge the job.
|
201
|
+
ack = true
|
202
|
+
e = h.cause || h
|
203
|
+
handle_exception(e, {context: "Job raised exception", job: job_hash})
|
204
|
+
raise e
|
205
|
+
rescue Exception => ex
|
206
|
+
# Unexpected error! This is very bad and indicates an exception that got past
|
207
|
+
# the retry subsystem (e.g. network partition). We won't acknowledge the job
|
208
|
+
# so it can be rescued when using Sidekiq Pro.
|
209
|
+
handle_exception(ex, {context: "Internal exception!", job: job_hash, jobstr: jobstr})
|
210
|
+
raise ex
|
172
211
|
end
|
173
|
-
ack = true
|
174
|
-
rescue Sidekiq::Shutdown
|
175
|
-
# Had to force kill this job because it didn't finish
|
176
|
-
# within the timeout. Don't acknowledge the work since
|
177
|
-
# we didn't properly finish it.
|
178
|
-
rescue Sidekiq::JobRetry::Handled => h
|
179
|
-
# this is the common case: job raised error and Sidekiq::JobRetry::Handled
|
180
|
-
# signals that we created a retry successfully. We can acknowlege the job.
|
181
|
-
ack = true
|
182
|
-
e = h.cause || h
|
183
|
-
handle_exception(e, {context: "Job raised exception", job: job_hash})
|
184
|
-
raise e
|
185
|
-
rescue Exception => ex
|
186
|
-
# Unexpected error! This is very bad and indicates an exception that got past
|
187
|
-
# the retry subsystem (e.g. network partition). We won't acknowledge the job
|
188
|
-
# so it can be rescued when using Sidekiq Pro.
|
189
|
-
handle_exception(ex, {context: "Internal exception!", job: job_hash, jobstr: jobstr})
|
190
|
-
raise ex
|
191
212
|
ensure
|
192
213
|
if ack
|
193
|
-
|
194
|
-
Thread.handle_interrupt(Sidekiq::Shutdown => :never) do
|
195
|
-
uow.acknowledge
|
196
|
-
end
|
214
|
+
uow.acknowledge
|
197
215
|
end
|
198
216
|
end
|
199
217
|
end
|
200
218
|
|
201
|
-
def execute_job(
|
202
|
-
|
219
|
+
def execute_job(instance, cloned_args)
|
220
|
+
instance.perform(*cloned_args)
|
203
221
|
end
|
204
222
|
|
205
223
|
# Ruby doesn't provide atomic counters out of the box so we'll
|
@@ -269,18 +287,5 @@ module Sidekiq
|
|
269
287
|
PROCESSED.incr
|
270
288
|
end
|
271
289
|
end
|
272
|
-
|
273
|
-
def constantize(str)
|
274
|
-
return Object.const_get(str) unless str.include?("::")
|
275
|
-
|
276
|
-
names = str.split("::")
|
277
|
-
names.shift if names.empty? || names.first.empty?
|
278
|
-
|
279
|
-
names.inject(Object) do |constant, name|
|
280
|
-
# the false flag limits search for name to under the constant namespace
|
281
|
-
# which mimics Rails' behaviour
|
282
|
-
constant.const_get(name, false)
|
283
|
-
end
|
284
|
-
end
|
285
290
|
end
|
286
291
|
end
|
data/lib/sidekiq/rails.rb
CHANGED
@@ -1,8 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "sidekiq/job"
|
4
|
+
require "rails"
|
4
5
|
|
5
6
|
module Sidekiq
|
7
|
+
module ActiveJob
|
8
|
+
# @api private
|
9
|
+
class Wrapper
|
10
|
+
include Sidekiq::Job
|
11
|
+
|
12
|
+
def perform(job_data)
|
13
|
+
::ActiveJob::Base.execute(job_data.merge("provider_job_id" => jid))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
6
18
|
class Rails < ::Rails::Engine
|
7
19
|
class Reloader
|
8
20
|
def initialize(app = ::Rails.application)
|
@@ -10,7 +22,8 @@ module Sidekiq
|
|
10
22
|
end
|
11
23
|
|
12
24
|
def call
|
13
|
-
|
25
|
+
params = (::Rails::VERSION::STRING >= "7.1") ? {source: "job.sidekiq"} : {}
|
26
|
+
@app.reloader.wrap(**params) do
|
14
27
|
yield
|
15
28
|
end
|
16
29
|
end
|
@@ -18,11 +31,15 @@ module Sidekiq
|
|
18
31
|
def inspect
|
19
32
|
"#<Sidekiq::Rails::Reloader @app=#{@app.class.name}>"
|
20
33
|
end
|
34
|
+
|
35
|
+
def to_hash
|
36
|
+
{app: @app.class.name}
|
37
|
+
end
|
21
38
|
end
|
22
39
|
|
23
40
|
# By including the Options module, we allow AJs to directly control sidekiq features
|
24
41
|
# via the *sidekiq_options* class method and, for instance, not use AJ's retry system.
|
25
|
-
# AJ retries don't show up in the Sidekiq UI Retries tab, save any error data, can't be
|
42
|
+
# AJ retries don't show up in the Sidekiq UI Retries tab, don't save any error data, can't be
|
26
43
|
# manually retried, don't automatically die, etc.
|
27
44
|
#
|
28
45
|
# class SomeJob < ActiveJob::Base
|
@@ -33,15 +50,15 @@ module Sidekiq
|
|
33
50
|
# end
|
34
51
|
initializer "sidekiq.active_job_integration" do
|
35
52
|
ActiveSupport.on_load(:active_job) do
|
53
|
+
require_relative "../active_job/queue_adapters/sidekiq_adapter"
|
36
54
|
include ::Sidekiq::Job::Options unless respond_to?(:sidekiq_options)
|
37
55
|
end
|
38
56
|
end
|
39
57
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
"default_worker_options=": :default_job_options=)
|
58
|
+
initializer "sidekiq.backtrace_cleaner" do
|
59
|
+
Sidekiq.configure_server do |config|
|
60
|
+
config[:backtrace_cleaner] = ->(backtrace) { ::Rails.backtrace_cleaner.clean(backtrace) }
|
61
|
+
end
|
45
62
|
end
|
46
63
|
|
47
64
|
# This hook happens after all initializers are run, just before returning
|
@@ -55,10 +72,10 @@ module Sidekiq
|
|
55
72
|
# This is the integration code necessary so that if a job uses `Rails.logger.info "Hello"`,
|
56
73
|
# it will appear in the Sidekiq console with all of the job context.
|
57
74
|
unless ::Rails.logger == config.logger || ::ActiveSupport::Logger.logger_outputs_to?(::Rails.logger, $stdout)
|
58
|
-
if ::Rails
|
59
|
-
::Rails.logger.extend(::ActiveSupport::Logger.broadcast(config.logger))
|
60
|
-
else
|
75
|
+
if ::Rails.logger.respond_to?(:broadcast_to)
|
61
76
|
::Rails.logger.broadcast_to(config.logger)
|
77
|
+
else
|
78
|
+
::Rails.logger.extend(::ActiveSupport::Logger.broadcast(config.logger))
|
62
79
|
end
|
63
80
|
end
|
64
81
|
end
|