sidekiq 7.1.2 → 7.1.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|