sidekiq 6.4.0 → 6.4.2
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 might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Changes.md +30 -1
- data/README.md +6 -1
- data/bin/sidekiq +3 -3
- data/bin/sidekiqload +57 -65
- data/bin/sidekiqmon +1 -1
- data/lib/sidekiq/api.rb +62 -58
- data/lib/sidekiq/cli.rb +14 -6
- data/lib/sidekiq/client.rb +41 -27
- data/lib/sidekiq/delay.rb +1 -1
- data/lib/sidekiq/extensions/action_mailer.rb +2 -2
- data/lib/sidekiq/extensions/active_record.rb +2 -2
- data/lib/sidekiq/extensions/class_methods.rb +2 -2
- data/lib/sidekiq/extensions/generic_proxy.rb +3 -3
- data/lib/sidekiq/fetch.rb +2 -2
- data/lib/sidekiq/job_logger.rb +15 -27
- data/lib/sidekiq/job_retry.rb +23 -23
- data/lib/sidekiq/job_util.rb +8 -6
- data/lib/sidekiq/launcher.rb +37 -36
- data/lib/sidekiq/logger.rb +8 -18
- data/lib/sidekiq/manager.rb +6 -6
- data/lib/sidekiq/middleware/chain.rb +4 -4
- data/lib/sidekiq/middleware/i18n.rb +4 -4
- data/lib/sidekiq/monitor.rb +1 -1
- data/lib/sidekiq/paginator.rb +8 -8
- data/lib/sidekiq/processor.rb +27 -27
- data/lib/sidekiq/rails.rb +10 -3
- data/lib/sidekiq/redis_connection.rb +2 -2
- data/lib/sidekiq/testing/inline.rb +4 -4
- data/lib/sidekiq/testing.rb +36 -35
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/csrf_protection.rb +2 -2
- data/lib/sidekiq/web/helpers.rb +4 -4
- data/lib/sidekiq/web.rb +3 -3
- data/lib/sidekiq/worker.rb +19 -17
- data/lib/sidekiq.rb +22 -15
- data/web/assets/javascripts/application.js +58 -26
- data/web/assets/stylesheets/application.css +1 -0
- data/web/views/_summary.erb +1 -1
- data/web/views/busy.erb +3 -3
- metadata +3 -3
data/lib/sidekiq/worker.rb
CHANGED
@@ -82,7 +82,7 @@ module Sidekiq
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def get_sidekiq_options # :nodoc:
|
85
|
-
self.sidekiq_options_hash ||= Sidekiq.
|
85
|
+
self.sidekiq_options_hash ||= Sidekiq.default_job_options
|
86
86
|
end
|
87
87
|
|
88
88
|
def sidekiq_class_attribute(*attrs)
|
@@ -175,16 +175,18 @@ module Sidekiq
|
|
175
175
|
|
176
176
|
def initialize(klass, opts)
|
177
177
|
@klass = klass
|
178
|
-
|
178
|
+
# NB: the internal hash always has stringified keys
|
179
|
+
@opts = opts.transform_keys(&:to_s)
|
179
180
|
|
180
181
|
# ActiveJob compatibility
|
181
|
-
interval = @opts.delete(
|
182
|
+
interval = @opts.delete("wait_until") || @opts.delete("wait")
|
182
183
|
at(interval) if interval
|
183
184
|
end
|
184
185
|
|
185
186
|
def set(options)
|
186
|
-
|
187
|
-
@opts.
|
187
|
+
hash = options.transform_keys(&:to_s)
|
188
|
+
interval = hash.delete("wait_until") || @opts.delete("wait")
|
189
|
+
@opts.merge!(hash)
|
188
190
|
at(interval) if interval
|
189
191
|
self
|
190
192
|
end
|
@@ -200,7 +202,7 @@ module Sidekiq
|
|
200
202
|
# Explicit inline execution of a job. Returns nil if the job did not
|
201
203
|
# execute, true otherwise.
|
202
204
|
def perform_inline(*args)
|
203
|
-
raw = @opts.merge("args" => args, "class" => @klass)
|
205
|
+
raw = @opts.merge("args" => args, "class" => @klass)
|
204
206
|
|
205
207
|
# validate and normalize payload
|
206
208
|
item = normalize_item(raw)
|
@@ -235,9 +237,9 @@ module Sidekiq
|
|
235
237
|
alias_method :perform_sync, :perform_inline
|
236
238
|
|
237
239
|
def perform_bulk(args, batch_size: 1_000)
|
238
|
-
|
240
|
+
client = @klass.build_client
|
239
241
|
result = args.each_slice(batch_size).flat_map do |slice|
|
240
|
-
|
242
|
+
client.push_bulk(@opts.merge("class" => @klass, "args" => slice))
|
241
243
|
end
|
242
244
|
|
243
245
|
result.is_a?(Enumerator::Lazy) ? result.force : result
|
@@ -291,6 +293,7 @@ module Sidekiq
|
|
291
293
|
def perform_inline(*args)
|
292
294
|
Setter.new(self, {}).perform_inline(*args)
|
293
295
|
end
|
296
|
+
alias_method :perform_sync, :perform_inline
|
294
297
|
|
295
298
|
##
|
296
299
|
# Push a large number of jobs to Redis, while limiting the batch of
|
@@ -312,12 +315,8 @@ module Sidekiq
|
|
312
315
|
#
|
313
316
|
# SomeWorker.perform_bulk([[1], [2], [3]])
|
314
317
|
#
|
315
|
-
def perform_bulk(
|
316
|
-
|
317
|
-
Sidekiq::Client.push_bulk("class" => self, "args" => slice)
|
318
|
-
end
|
319
|
-
|
320
|
-
result.is_a?(Enumerator::Lazy) ? result.force : result
|
318
|
+
def perform_bulk(*args, **kwargs)
|
319
|
+
Setter.new(self, {}).perform_bulk(*args, **kwargs)
|
321
320
|
end
|
322
321
|
|
323
322
|
# +interval+ must be a timestamp, numeric or something that acts
|
@@ -354,10 +353,13 @@ module Sidekiq
|
|
354
353
|
end
|
355
354
|
|
356
355
|
def client_push(item) # :nodoc:
|
357
|
-
|
358
|
-
|
356
|
+
raise ArgumentError, "Job payloads should contain no Symbols: #{item}" if item.any? { |k, v| k.is_a?(::Symbol) }
|
357
|
+
build_client.push(item)
|
358
|
+
end
|
359
359
|
|
360
|
-
|
360
|
+
def build_client # :nodoc:
|
361
|
+
pool = Thread.current[:sidekiq_via_pool] || get_sidekiq_options["pool"] || Sidekiq.redis_pool
|
362
|
+
Sidekiq::Client.new(pool)
|
361
363
|
end
|
362
364
|
end
|
363
365
|
end
|
data/lib/sidekiq.rb
CHANGED
@@ -40,11 +40,6 @@ module Sidekiq
|
|
40
40
|
reloader: proc { |&block| block.call }
|
41
41
|
}
|
42
42
|
|
43
|
-
DEFAULT_WORKER_OPTIONS = {
|
44
|
-
"retry" => true,
|
45
|
-
"queue" => "default"
|
46
|
-
}
|
47
|
-
|
48
43
|
FAKE_INFO = {
|
49
44
|
"redis_version" => "9.9.9",
|
50
45
|
"uptime_in_days" => "9999",
|
@@ -103,6 +98,7 @@ module Sidekiq
|
|
103
98
|
# to disconnect and reopen the socket to get back to the primary.
|
104
99
|
# 4495 Use the same logic if we have a "Not enough replicas" error from the primary
|
105
100
|
# 4985 Use the same logic when a blocking command is force-unblocked
|
101
|
+
# The same retry logic is also used in client.rb
|
106
102
|
if retryable && ex.message =~ /READONLY|NOREPLICAS|UNBLOCKED/
|
107
103
|
conn.disconnect!
|
108
104
|
retryable = false
|
@@ -157,13 +153,20 @@ module Sidekiq
|
|
157
153
|
Middleware::Chain.new
|
158
154
|
end
|
159
155
|
|
160
|
-
def self.default_worker_options=(hash)
|
161
|
-
|
162
|
-
|
156
|
+
def self.default_worker_options=(hash) # deprecated
|
157
|
+
@default_job_options = default_job_options.merge(hash.transform_keys(&:to_s))
|
158
|
+
end
|
159
|
+
|
160
|
+
def self.default_job_options=(hash)
|
161
|
+
@default_job_options = default_job_options.merge(hash.transform_keys(&:to_s))
|
163
162
|
end
|
164
163
|
|
165
|
-
def self.default_worker_options
|
166
|
-
|
164
|
+
def self.default_worker_options # deprecated
|
165
|
+
@default_job_options ||= {"retry" => true, "queue" => "default"}
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.default_job_options
|
169
|
+
@default_job_options ||= {"retry" => true, "queue" => "default"}
|
167
170
|
end
|
168
171
|
|
169
172
|
##
|
@@ -201,12 +204,12 @@ module Sidekiq
|
|
201
204
|
end
|
202
205
|
|
203
206
|
def self.logger
|
204
|
-
@logger ||= Sidekiq::Logger.new($stdout, level:
|
207
|
+
@logger ||= Sidekiq::Logger.new($stdout, level: :info)
|
205
208
|
end
|
206
209
|
|
207
210
|
def self.logger=(logger)
|
208
211
|
if logger.nil?
|
209
|
-
self.logger.
|
212
|
+
self.logger.fatal!
|
210
213
|
return self.logger
|
211
214
|
end
|
212
215
|
|
@@ -219,6 +222,10 @@ module Sidekiq
|
|
219
222
|
defined?(Sidekiq::Pro)
|
220
223
|
end
|
221
224
|
|
225
|
+
def self.ent?
|
226
|
+
defined?(Sidekiq::Enterprise)
|
227
|
+
end
|
228
|
+
|
222
229
|
# How frequently Redis should be checked by a random Sidekiq process for
|
223
230
|
# scheduled and retriable jobs. Each individual process will take turns by
|
224
231
|
# waiting some multiple of this value.
|
@@ -257,12 +264,12 @@ module Sidekiq
|
|
257
264
|
options[:on_complex_arguments] = mode
|
258
265
|
end
|
259
266
|
|
260
|
-
# We are shutting down Sidekiq but what about
|
267
|
+
# We are shutting down Sidekiq but what about threads that
|
261
268
|
# are working on some long job? This error is
|
262
|
-
# raised in
|
269
|
+
# raised in jobs that have not finished within the hard
|
263
270
|
# timeout limit. This is needed to rollback db transactions,
|
264
271
|
# otherwise Ruby's Thread#kill will commit. See #377.
|
265
|
-
# DO NOT RESCUE THIS ERROR IN YOUR
|
272
|
+
# DO NOT RESCUE THIS ERROR IN YOUR JOBS
|
266
273
|
class Shutdown < Interrupt; end
|
267
274
|
end
|
268
275
|
|
@@ -9,7 +9,9 @@ var ready = (callback) => {
|
|
9
9
|
else document.addEventListener("DOMContentLoaded", callback);
|
10
10
|
}
|
11
11
|
|
12
|
-
ready(
|
12
|
+
ready(addListeners)
|
13
|
+
|
14
|
+
function addListeners() {
|
13
15
|
document.querySelectorAll(".check_all").forEach(node => {
|
14
16
|
node.addEventListener("click", event => {
|
15
17
|
node.closest('table').querySelectorAll('input[type=checkbox]').forEach(inp => { inp.checked = !!node.checked; });
|
@@ -26,42 +28,48 @@ ready(() => {
|
|
26
28
|
})
|
27
29
|
|
28
30
|
document.querySelectorAll("[data-toggle]").forEach(node => {
|
29
|
-
node.addEventListener("click",
|
30
|
-
var targName = node.getAttribute("data-toggle");
|
31
|
-
var full = document.getElementById(targName + "_full");
|
32
|
-
if (full.style.display == "block") {
|
33
|
-
full.style.display = 'none';
|
34
|
-
} else {
|
35
|
-
full.style.display = 'block';
|
36
|
-
}
|
37
|
-
})
|
31
|
+
node.addEventListener("click", addDataToggleListeners)
|
38
32
|
})
|
39
33
|
|
40
34
|
updateFuzzyTimes();
|
35
|
+
setLivePollFromUrl();
|
41
36
|
|
42
37
|
var buttons = document.querySelectorAll(".live-poll");
|
43
38
|
if (buttons.length > 0) {
|
44
39
|
buttons.forEach(node => {
|
45
|
-
node.addEventListener("click",
|
46
|
-
if (localStorage.sidekiqLivePoll == "enabled") {
|
47
|
-
localStorage.sidekiqLivePoll = "disabled";
|
48
|
-
clearTimeout(livePollTimer);
|
49
|
-
livePollTimer = null;
|
50
|
-
} else {
|
51
|
-
localStorage.sidekiqLivePoll = "enabled";
|
52
|
-
livePollCallback();
|
53
|
-
}
|
54
|
-
|
55
|
-
updateLivePollButton();
|
56
|
-
})
|
40
|
+
node.addEventListener("click", addPollingListeners)
|
57
41
|
});
|
58
42
|
|
59
43
|
updateLivePollButton();
|
60
|
-
if (localStorage.sidekiqLivePoll == "enabled") {
|
44
|
+
if (localStorage.sidekiqLivePoll == "enabled" && !livePollTimer) {
|
61
45
|
scheduleLivePoll();
|
62
46
|
}
|
63
47
|
}
|
64
|
-
}
|
48
|
+
}
|
49
|
+
|
50
|
+
function addPollingListeners(_event) {
|
51
|
+
if (localStorage.sidekiqLivePoll == "enabled") {
|
52
|
+
localStorage.sidekiqLivePoll = "disabled";
|
53
|
+
clearTimeout(livePollTimer);
|
54
|
+
livePollTimer = null;
|
55
|
+
} else {
|
56
|
+
localStorage.sidekiqLivePoll = "enabled";
|
57
|
+
livePollCallback();
|
58
|
+
}
|
59
|
+
|
60
|
+
updateLivePollButton();
|
61
|
+
}
|
62
|
+
|
63
|
+
function addDataToggleListeners(event) {
|
64
|
+
var source = event.target || event.srcElement;
|
65
|
+
var targName = source.getAttribute("data-toggle");
|
66
|
+
var full = document.getElementById(targName + "_full");
|
67
|
+
if (full.style.display == "block") {
|
68
|
+
full.style.display = 'none';
|
69
|
+
} else {
|
70
|
+
full.style.display = 'block';
|
71
|
+
}
|
72
|
+
}
|
65
73
|
|
66
74
|
function updateFuzzyTimes() {
|
67
75
|
var locale = document.body.getAttribute("data-locale");
|
@@ -76,6 +84,14 @@ function updateFuzzyTimes() {
|
|
76
84
|
t.cancel();
|
77
85
|
}
|
78
86
|
|
87
|
+
function setLivePollFromUrl() {
|
88
|
+
var url_params = new URL(window.location.href).searchParams
|
89
|
+
|
90
|
+
if (url_params.get("poll") == "true") {
|
91
|
+
localStorage.sidekiqLivePoll = "enabled";
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
79
95
|
function updateLivePollButton() {
|
80
96
|
if (localStorage.sidekiqLivePoll == "enabled") {
|
81
97
|
document.querySelectorAll('.live-poll-stop').forEach(box => { box.style.display = "inline-block" })
|
@@ -89,7 +105,19 @@ function updateLivePollButton() {
|
|
89
105
|
function livePollCallback() {
|
90
106
|
clearTimeout(livePollTimer);
|
91
107
|
|
92
|
-
fetch(window.location.href)
|
108
|
+
fetch(window.location.href)
|
109
|
+
.then(checkResponse)
|
110
|
+
.then(resp => resp.text())
|
111
|
+
.then(replacePage)
|
112
|
+
.catch(showError)
|
113
|
+
.finally(scheduleLivePoll)
|
114
|
+
}
|
115
|
+
|
116
|
+
function checkResponse(resp) {
|
117
|
+
if (!resp.ok) {
|
118
|
+
throw response.error();
|
119
|
+
}
|
120
|
+
return resp
|
93
121
|
}
|
94
122
|
|
95
123
|
function scheduleLivePoll() {
|
@@ -107,5 +135,9 @@ function replacePage(text) {
|
|
107
135
|
var header_status = doc.querySelector('.status')
|
108
136
|
document.querySelector('.status').replaceWith(header_status)
|
109
137
|
|
110
|
-
|
138
|
+
addListeners();
|
139
|
+
}
|
140
|
+
|
141
|
+
function showError(error) {
|
142
|
+
console.error(error)
|
111
143
|
}
|
data/web/views/_summary.erb
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
</li>
|
10
10
|
<li class="busy col-sm-1">
|
11
11
|
<a href="<%= root_path %>busy">
|
12
|
-
<span id="txtBusy" class="count"><%= number_with_delimiter(
|
12
|
+
<span id="txtBusy" class="count"><%= number_with_delimiter(workset.size) %></span>
|
13
13
|
<span class="desc"><%= t('Busy') %></span>
|
14
14
|
</a>
|
15
15
|
</li>
|
data/web/views/busy.erb
CHANGED
@@ -15,7 +15,7 @@
|
|
15
15
|
<p><%= t('Threads') %></p>
|
16
16
|
</div>
|
17
17
|
<div class="stat">
|
18
|
-
<h3><%= ws =
|
18
|
+
<h3><%= ws = workset.size; number_with_delimiter(ws) %></h3>
|
19
19
|
<p><%= t('Busy') %></p>
|
20
20
|
</div>
|
21
21
|
<div class="stat">
|
@@ -48,7 +48,7 @@
|
|
48
48
|
<thead>
|
49
49
|
<th><%= t('Name') %></th>
|
50
50
|
<th><%= t('Started') %></th>
|
51
|
-
<th class="col-sm-1"><%= t('RSS') %><a href="https://github.com/mperham/sidekiq/wiki/Memory#rss"><span class="info-circle" title="Click to learn more about RSS">?</span></a></th>
|
51
|
+
<th class="col-sm-1"><%= t('RSS') %><a target="blank" href="https://github.com/mperham/sidekiq/wiki/Memory#rss"><span class="info-circle" title="Click to learn more about RSS">?</span></a></th>
|
52
52
|
<th class="col-sm-1"><%= t('Threads') %></th>
|
53
53
|
<th class="col-sm-1"><%= t('Busy') %></th>
|
54
54
|
<th> </th>
|
@@ -109,7 +109,7 @@
|
|
109
109
|
<th><%= t('Arguments') %></th>
|
110
110
|
<th><%= t('Started') %></th>
|
111
111
|
</thead>
|
112
|
-
<%
|
112
|
+
<% workset.each do |process, thread, msg| %>
|
113
113
|
<% job = Sidekiq::JobRecord.new(msg['payload']) %>
|
114
114
|
<tr>
|
115
115
|
<td><%= process %></td>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.4.
|
4
|
+
version: 6.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Perham
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -193,7 +193,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
193
193
|
- !ruby/object:Gem::Version
|
194
194
|
version: '0'
|
195
195
|
requirements: []
|
196
|
-
rubygems_version: 3.
|
196
|
+
rubygems_version: 3.2.32
|
197
197
|
signing_key:
|
198
198
|
specification_version: 4
|
199
199
|
summary: Simple, efficient background processing for Ruby
|