sidekiq 7.1.2 → 7.1.3
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 +9 -0
- data/lib/sidekiq/client.rb +1 -0
- data/lib/sidekiq/job_retry.rb +17 -2
- data/lib/sidekiq/job_util.rb +2 -0
- data/lib/sidekiq/metrics/shared.rb +1 -1
- data/lib/sidekiq/processor.rb +27 -26
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/action.rb +3 -3
- data/lib/sidekiq/web/application.rb +5 -5
- data/lib/sidekiq/web/csrf_protection.rb +1 -1
- data/lib/sidekiq/web.rb +13 -1
- data/web/assets/javascripts/application.js +1 -0
- data/web/assets/javascripts/dashboard-charts.js +3 -1
- data/web/locales/pt-br.yml +20 -0
- data/web/views/_job_info.erb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03e85917d2ea03bf226aa6922510b627931c326eb31badf50cc23f39182fc409
|
4
|
+
data.tar.gz: '00180ea8ecb3013a8a405eecd0c6051c3611de72e668a9ce1da695fdbfd34a59'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 607e2599f0500af84ced9b8e0b4ed34d1cf947d1e0c7d144ab1a03f5f0652cdda97d097422b6beba8b76f5c78381d29cdde784b1c7463aa006d009304739acaa
|
7
|
+
data.tar.gz: 9a7758f5bd266711d56bd2df5275d9d942d1ca3e586f5e5eb945dd2a62a7bac5f4f54f058d41a2c747da301d691c7cceb47ef641f2d0a2cc2716051914d9646a
|
data/Changes.md
CHANGED
@@ -2,6 +2,15 @@
|
|
2
2
|
|
3
3
|
[Sidekiq Changes](https://github.com/sidekiq/sidekiq/blob/main/Changes.md) | [Sidekiq Pro Changes](https://github.com/sidekiq/sidekiq/blob/main/Pro-Changes.md) | [Sidekiq Enterprise Changes](https://github.com/sidekiq/sidekiq/blob/main/Ent-Changes.md)
|
4
4
|
|
5
|
+
7.1.3
|
6
|
+
----------
|
7
|
+
|
8
|
+
- Add `sidekiq_options retry_for: 48.hours` to allow time-based retry windows [#6029]
|
9
|
+
- Support sidekiq_retry_in and sidekiq_retries_exhausted_block in ActiveJobs (#5994)
|
10
|
+
- Lowercase all Rack headers for Rack 3.0 [#5951]
|
11
|
+
- Validate Sidekiq::Web page refresh delay to avoid potential DoS,
|
12
|
+
CVE-2023-26141, thanks for reporting Keegan!
|
13
|
+
|
5
14
|
7.1.2
|
6
15
|
----------
|
7
16
|
|
data/lib/sidekiq/client.rb
CHANGED
@@ -66,6 +66,7 @@ module Sidekiq
|
|
66
66
|
# args - an array of simple arguments to the perform method, must be JSON-serializable
|
67
67
|
# at - timestamp to schedule the job (optional), must be Numeric (e.g. Time.now.to_f)
|
68
68
|
# retry - whether to retry this job if it fails, default true or an integer number of retries
|
69
|
+
# retry_for - relative amount of time to retry this job if it fails, default nil
|
69
70
|
# backtrace - whether to save any error backtrace, default false
|
70
71
|
#
|
71
72
|
# If class is set to the class name, the jobs' options will be based on Sidekiq's default
|
data/lib/sidekiq/job_retry.rb
CHANGED
@@ -170,9 +170,11 @@ module Sidekiq
|
|
170
170
|
msg["error_backtrace"] = compress_backtrace(lines)
|
171
171
|
end
|
172
172
|
|
173
|
-
# Goodbye dear message, you (re)tried your best I'm sure.
|
174
173
|
return retries_exhausted(jobinst, msg, exception) if count >= max_retry_attempts
|
175
174
|
|
175
|
+
rf = msg["retry_for"]
|
176
|
+
return retries_exhausted(jobinst, msg, exception) if rf && ((msg["failed_at"] + rf) < Time.now.to_f)
|
177
|
+
|
176
178
|
strategy, delay = delay_for(jobinst, count, exception, msg)
|
177
179
|
case strategy
|
178
180
|
when :discard
|
@@ -197,7 +199,14 @@ module Sidekiq
|
|
197
199
|
# sidekiq_retry_in can return two different things:
|
198
200
|
# 1. When to retry next, as an integer of seconds
|
199
201
|
# 2. A symbol which re-routes the job elsewhere, e.g. :discard, :kill, :default
|
200
|
-
jobinst&.sidekiq_retry_in_block
|
202
|
+
block = jobinst&.sidekiq_retry_in_block
|
203
|
+
|
204
|
+
# the sidekiq_retry_in_block can be defined in a wrapped class (ActiveJob for instance)
|
205
|
+
unless msg["wrapped"].nil?
|
206
|
+
wrapped = Object.const_get(msg["wrapped"])
|
207
|
+
block = wrapped.respond_to?(:sidekiq_retry_in_block) ? wrapped.sidekiq_retry_in_block : nil
|
208
|
+
end
|
209
|
+
block&.call(count, exception, msg)
|
201
210
|
rescue Exception => e
|
202
211
|
handle_exception(e, {context: "Failure scheduling retry using the defined `sidekiq_retry_in` in #{jobinst.class.name}, falling back to default"})
|
203
212
|
nil
|
@@ -219,6 +228,12 @@ module Sidekiq
|
|
219
228
|
def retries_exhausted(jobinst, msg, exception)
|
220
229
|
begin
|
221
230
|
block = jobinst&.sidekiq_retries_exhausted_block
|
231
|
+
|
232
|
+
# the sidekiq_retries_exhausted_block can be defined in a wrapped class (ActiveJob for instance)
|
233
|
+
unless msg["wrapped"].nil?
|
234
|
+
wrapped = Object.const_get(msg["wrapped"])
|
235
|
+
block = wrapped.respond_to?(:sidekiq_retries_exhausted_block) ? wrapped.sidekiq_retries_exhausted_block : nil
|
236
|
+
end
|
222
237
|
block&.call(msg, exception)
|
223
238
|
rescue => e
|
224
239
|
handle_exception(e, {context: "Error calling retries_exhausted", job: msg})
|
data/lib/sidekiq/job_util.rb
CHANGED
@@ -13,6 +13,7 @@ module Sidekiq
|
|
13
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
14
|
raise(ArgumentError, "Job 'at' must be a Numeric timestamp: `#{item}`") if item.key?("at") && !item["at"].is_a?(Numeric)
|
15
15
|
raise(ArgumentError, "Job tags must be an Array: `#{item}`") if item["tags"] && !item["tags"].is_a?(Array)
|
16
|
+
raise(ArgumentError, "retry_for must be a relative amount of time, e.g. 48.hours `#{item}`") if item["retry_for"] && item["retry_for"] > 1_000_000_000
|
16
17
|
end
|
17
18
|
|
18
19
|
def verify_json(item)
|
@@ -54,6 +55,7 @@ module Sidekiq
|
|
54
55
|
item["jid"] ||= SecureRandom.hex(12)
|
55
56
|
item["class"] = item["class"].to_s
|
56
57
|
item["queue"] = item["queue"].to_s
|
58
|
+
item["retry_for"] = item["retry_for"].to_i
|
57
59
|
item["created_at"] ||= Time.now.to_f
|
58
60
|
item
|
59
61
|
end
|
data/lib/sidekiq/processor.rb
CHANGED
@@ -148,6 +148,8 @@ module Sidekiq
|
|
148
148
|
|
149
149
|
IGNORE_SHUTDOWN_INTERRUPTS = {Sidekiq::Shutdown => :never}
|
150
150
|
private_constant :IGNORE_SHUTDOWN_INTERRUPTS
|
151
|
+
ALLOW_SHUTDOWN_INTERRUPTS = {Sidekiq::Shutdown => :immediate}
|
152
|
+
private_constant :ALLOW_SHUTDOWN_INTERRUPTS
|
151
153
|
|
152
154
|
def process(uow)
|
153
155
|
jobstr = uow.job
|
@@ -171,36 +173,35 @@ module Sidekiq
|
|
171
173
|
end
|
172
174
|
|
173
175
|
ack = false
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
176
|
+
Thread.handle_interrupt(IGNORE_SHUTDOWN_INTERRUPTS) do
|
177
|
+
Thread.handle_interrupt(ALLOW_SHUTDOWN_INTERRUPTS) do
|
178
|
+
dispatch(job_hash, queue, jobstr) do |inst|
|
179
|
+
config.server_middleware.invoke(inst, job_hash, queue) do
|
180
|
+
execute_job(inst, job_hash["args"])
|
181
|
+
end
|
178
182
|
end
|
183
|
+
ack = true
|
184
|
+
rescue Sidekiq::Shutdown
|
185
|
+
# Had to force kill this job because it didn't finish
|
186
|
+
# within the timeout. Don't acknowledge the work since
|
187
|
+
# we didn't properly finish it.
|
188
|
+
rescue Sidekiq::JobRetry::Handled => h
|
189
|
+
# this is the common case: job raised error and Sidekiq::JobRetry::Handled
|
190
|
+
# signals that we created a retry successfully. We can acknowlege the job.
|
191
|
+
ack = true
|
192
|
+
e = h.cause || h
|
193
|
+
handle_exception(e, {context: "Job raised exception", job: job_hash})
|
194
|
+
raise e
|
195
|
+
rescue Exception => ex
|
196
|
+
# Unexpected error! This is very bad and indicates an exception that got past
|
197
|
+
# the retry subsystem (e.g. network partition). We won't acknowledge the job
|
198
|
+
# so it can be rescued when using Sidekiq Pro.
|
199
|
+
handle_exception(ex, {context: "Internal exception!", job: job_hash, jobstr: jobstr})
|
200
|
+
raise ex
|
179
201
|
end
|
180
|
-
ack = true
|
181
|
-
rescue Sidekiq::Shutdown
|
182
|
-
# Had to force kill this job because it didn't finish
|
183
|
-
# within the timeout. Don't acknowledge the work since
|
184
|
-
# we didn't properly finish it.
|
185
|
-
rescue Sidekiq::JobRetry::Handled => h
|
186
|
-
# this is the common case: job raised error and Sidekiq::JobRetry::Handled
|
187
|
-
# signals that we created a retry successfully. We can acknowlege the job.
|
188
|
-
ack = true
|
189
|
-
e = h.cause || h
|
190
|
-
handle_exception(e, {context: "Job raised exception", job: job_hash})
|
191
|
-
raise e
|
192
|
-
rescue Exception => ex
|
193
|
-
# Unexpected error! This is very bad and indicates an exception that got past
|
194
|
-
# the retry subsystem (e.g. network partition). We won't acknowledge the job
|
195
|
-
# so it can be rescued when using Sidekiq Pro.
|
196
|
-
handle_exception(ex, {context: "Internal exception!", job: job_hash, jobstr: jobstr})
|
197
|
-
raise ex
|
198
202
|
ensure
|
199
203
|
if ack
|
200
|
-
|
201
|
-
Thread.handle_interrupt(IGNORE_SHUTDOWN_INTERRUPTS) do
|
202
|
-
uow.acknowledge
|
203
|
-
end
|
204
|
+
uow.acknowledge
|
204
205
|
end
|
205
206
|
end
|
206
207
|
end
|
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/web/action.rb
CHANGED
@@ -15,11 +15,11 @@ module Sidekiq
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def halt(res)
|
18
|
-
throw :halt, [res, {
|
18
|
+
throw :halt, [res, {Rack::CONTENT_TYPE => "text/plain"}, [res.to_s]]
|
19
19
|
end
|
20
20
|
|
21
21
|
def redirect(location)
|
22
|
-
throw :halt, [302, {
|
22
|
+
throw :halt, [302, {Web::LOCATION => "#{request.base_url}#{location}"}, []]
|
23
23
|
end
|
24
24
|
|
25
25
|
def params
|
@@ -68,7 +68,7 @@ module Sidekiq
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def json(payload)
|
71
|
-
[200, {
|
71
|
+
[200, {Rack::CONTENT_TYPE => "application/json", Rack::CACHE_CONTROL => "private, no-store"}, [Sidekiq.dump_json(payload)]]
|
72
72
|
end
|
73
73
|
|
74
74
|
def initialize(env, block)
|
@@ -330,7 +330,7 @@ module Sidekiq
|
|
330
330
|
|
331
331
|
def call(env)
|
332
332
|
action = self.class.match(env)
|
333
|
-
return [404, {
|
333
|
+
return [404, {Rack::CONTENT_TYPE => "text/plain", Web::X_CASCADE => "pass"}, ["Not Found"]] unless action
|
334
334
|
|
335
335
|
app = @klass
|
336
336
|
resp = catch(:halt) do
|
@@ -347,10 +347,10 @@ module Sidekiq
|
|
347
347
|
else
|
348
348
|
# rendered content goes here
|
349
349
|
headers = {
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
350
|
+
Rack::CONTENT_TYPE => "text/html",
|
351
|
+
Rack::CACHE_CONTROL => "private, no-store",
|
352
|
+
Web::CONTENT_LANGUAGE => action.locale,
|
353
|
+
Web::CONTENT_SECURITY_POLICY => CSP_HEADER
|
354
354
|
}
|
355
355
|
# we'll let Rack calculate Content-Length for us.
|
356
356
|
[200, headers, [resp]]
|
data/lib/sidekiq/web.rb
CHANGED
@@ -34,6 +34,18 @@ module Sidekiq
|
|
34
34
|
"Metrics" => "metrics"
|
35
35
|
}
|
36
36
|
|
37
|
+
if Gem::Version.new(Rack::RELEASE) < Gem::Version.new("3")
|
38
|
+
CONTENT_LANGUAGE = "Content-Language"
|
39
|
+
CONTENT_SECURITY_POLICY = "Content-Security-Policy"
|
40
|
+
LOCATION = "Location"
|
41
|
+
X_CASCADE = "X-Cascade"
|
42
|
+
else
|
43
|
+
CONTENT_LANGUAGE = "content-language"
|
44
|
+
CONTENT_SECURITY_POLICY = "content-security-policy"
|
45
|
+
LOCATION = "location"
|
46
|
+
X_CASCADE = "x-cascade"
|
47
|
+
end
|
48
|
+
|
37
49
|
class << self
|
38
50
|
def settings
|
39
51
|
self
|
@@ -137,7 +149,7 @@ module Sidekiq
|
|
137
149
|
m = middlewares
|
138
150
|
|
139
151
|
rules = []
|
140
|
-
rules = [[:all, {
|
152
|
+
rules = [[:all, {Rack::CACHE_CONTROL => "private, max-age=86400"}]] unless ENV["SIDEKIQ_WEB_TESTING"]
|
141
153
|
|
142
154
|
::Rack::Builder.new do
|
143
155
|
use Rack::Static, urls: ["/stylesheets", "/images", "/javascripts"],
|
@@ -57,7 +57,9 @@ class DashboardChart extends BaseChart {
|
|
57
57
|
class RealtimeChart extends DashboardChart {
|
58
58
|
constructor(el, options) {
|
59
59
|
super(el, options);
|
60
|
-
|
60
|
+
let d = parseInt(localStorage.sidekiqTimeInterval) || 5000;
|
61
|
+
if (d < 2000) { d = 2000; }
|
62
|
+
this.delay = d
|
61
63
|
this.startPolling();
|
62
64
|
document.addEventListener("interval:update", this.handleUpdate.bind(this));
|
63
65
|
}
|
data/web/locales/pt-br.yml
CHANGED
@@ -5,10 +5,13 @@
|
|
5
5
|
AreYouSureDeleteJob: Deseja deletar esta tarefa?
|
6
6
|
AreYouSureDeleteQueue: Deseja deletar a fila %{queue}? Isso irá deletar todas as tarefas desta fila.
|
7
7
|
Arguments: Argumentos
|
8
|
+
AvgExecutionTime: Tempo médio de execução
|
8
9
|
BackToApp: De volta ao aplicativo
|
10
|
+
Bucket: Bucket
|
9
11
|
Busy: Ocupados
|
10
12
|
Class: Classe
|
11
13
|
Connections: Conexões
|
14
|
+
Context: Contexto
|
12
15
|
CreatedAt: Criado em
|
13
16
|
CurrentMessagesInQueue: Mensagens atualmente na <span class='title'>%{queue}</span>
|
14
17
|
Dashboard: Painel
|
@@ -16,13 +19,16 @@
|
|
16
19
|
DeadJobs: Tarefas mortas
|
17
20
|
Delete: Apagar
|
18
21
|
DeleteAll: Apagar tudo
|
22
|
+
Deploy: Deploy
|
19
23
|
Enqueued: Na fila
|
20
24
|
Error: Erro
|
21
25
|
ErrorBacktrace: Rastreamento do erro
|
22
26
|
ErrorClass: Classe de erro
|
23
27
|
ErrorMessage: Mensagem de erro
|
28
|
+
ExecutionTime: Tempo de execução
|
24
29
|
Extras: Extras
|
25
30
|
Failed: Falhas
|
31
|
+
Failure: Falha
|
26
32
|
Failures: Falhas
|
27
33
|
GoBack: ← Voltar
|
28
34
|
History: Histórico
|
@@ -34,10 +40,13 @@
|
|
34
40
|
Latency: Latência
|
35
41
|
LivePoll: Live Poll
|
36
42
|
MemoryUsage: Uso de memória
|
43
|
+
Metrics: Métricas
|
37
44
|
Name: Nome
|
38
45
|
Namespace: Namespace
|
39
46
|
NextRetry: Próxima Tentativa
|
47
|
+
NoDataFound: Nenhum dado encontrado
|
40
48
|
NoDeadJobsFound: Nenhuma tarefa morta foi encontrada
|
49
|
+
NoJobMetricsFound: Nenhuma métrica de tarefa encontrada
|
41
50
|
NoRetriesFound: Nenhuma tentativa encontrada
|
42
51
|
NoScheduledFound: Nenhuma tarefa agendada foi encontrada
|
43
52
|
NotYetEnqueued: Ainda não enfileirado
|
@@ -47,6 +56,7 @@
|
|
47
56
|
Pause: Pausar
|
48
57
|
Paused: Pausado
|
49
58
|
PeakMemoryUsage: Pico de uso de memória
|
59
|
+
Uptime: Tempo de atividade
|
50
60
|
Plugins: Plug-ins
|
51
61
|
PollingInterval: Intervalo de Polling
|
52
62
|
Process: Processo
|
@@ -63,14 +73,24 @@
|
|
63
73
|
RetryNow: Tentar novamente agora
|
64
74
|
Scheduled: Agendados
|
65
75
|
ScheduledJobs: Tarefas agendadas
|
76
|
+
idle: Ocioso
|
77
|
+
active: Ativo
|
78
|
+
Seconds: Segundos
|
66
79
|
ShowAll: Mostrar todos
|
67
80
|
SixMonths: 6 meses
|
68
81
|
Size: Tamanho
|
82
|
+
Started: Iniciado
|
69
83
|
Stop: Parar
|
70
84
|
StopAll: Parar Todos
|
71
85
|
StopPolling: Parar Polling
|
86
|
+
Success: Sucesso
|
87
|
+
Summary: Resumo
|
72
88
|
Thread: Thread
|
73
89
|
Threads: Threads
|
90
|
+
ThreeMonths: 3 meses
|
91
|
+
TotalExecutionTime: Tempo total de execução
|
74
92
|
Unpause: Despausar
|
75
93
|
Utilization: Utilização
|
94
|
+
Version: Versão
|
95
|
+
When: Quando
|
76
96
|
Worker: Trabalhador
|
data/web/views/_job_info.erb
CHANGED
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: 7.1.
|
4
|
+
version: 7.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Perham
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-09-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis-client
|