sidekiq 7.3.1 → 7.3.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 +31 -0
- data/lib/active_job/queue_adapters/sidekiq_adapter.rb +88 -0
- data/lib/sidekiq/api.rb +5 -5
- data/lib/sidekiq/capsule.rb +3 -3
- data/lib/sidekiq/client.rb +17 -0
- data/lib/sidekiq/config.rb +14 -2
- data/lib/sidekiq/job/iterable/active_record_enumerator.rb +3 -3
- data/lib/sidekiq/job/iterable.rb +69 -6
- data/lib/sidekiq/metrics/shared.rb +14 -5
- data/lib/sidekiq/middleware/current_attributes.rb +1 -1
- data/lib/sidekiq/processor.rb +10 -10
- data/lib/sidekiq/rails.rb +6 -0
- data/lib/sidekiq/testing.rb +5 -5
- data/lib/sidekiq/version.rb +5 -1
- data/lib/sidekiq/web/action.rb +6 -2
- data/lib/sidekiq/web/application.rb +6 -32
- data/lib/sidekiq/web/router.rb +5 -2
- data/lib/sidekiq/web.rb +1 -1
- data/lib/sidekiq.rb +4 -3
- data/sidekiq.gemspec +0 -1
- data/web/assets/stylesheets/application.css +4 -8
- data/web/locales/en.yml +0 -1
- data/web/locales/fr.yml +0 -1
- data/web/locales/gd.yml +0 -1
- data/web/locales/ja.yml +0 -1
- data/web/locales/pt-br.yml +1 -2
- data/web/locales/tr.yml +0 -1
- data/web/locales/uk.yml +24 -1
- data/web/locales/zh-cn.yml +0 -1
- data/web/locales/zh-tw.yml +0 -1
- data/web/views/metrics.erb +2 -2
- metadata +3 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f278eab88087d46198fc13a2f5019f1d7e399810ecfebeba5044ff9bfd25e271
|
4
|
+
data.tar.gz: fb790ae54375a60b30b9eaf6676291a8f42c5a17a9f9487c6f018447810bb46f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 676ca234e7ce2218a72266f793a686c4fe5c944535ad5a76d7b7c263190a1eccb9341c06fbff0ab2e11acd4875c5dee74d959b9d1019687904b8cb53a84a6267
|
7
|
+
data.tar.gz: ab7f1f5acbfc9064d93d8881354bd5a572a96f45f125c1074cf50212f23a1d60df8ac196843a45963064009f41e074eb322a50acb3680fd62ee727fcae36c14f
|
data/Changes.md
CHANGED
@@ -2,6 +2,37 @@
|
|
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.3.3
|
6
|
+
----------
|
7
|
+
|
8
|
+
- Freeze global configuration once boot is complete, to avoid configuration race conditions [#6466, #6465]
|
9
|
+
- Sidekiq now warns if a job iteration takes longer than the `-t` timeout setting (defaults to 25 seconds)
|
10
|
+
- Iteration callbacks now have easy access to job arguments via the `arguments` method:
|
11
|
+
```ruby
|
12
|
+
def on_stop
|
13
|
+
p arguments # => `[123, "string", {"key" => "value"}]`
|
14
|
+
id, str, hash = arguments
|
15
|
+
end
|
16
|
+
```
|
17
|
+
- Iterable jobs can be cancelled via `Sidekiq::Client#cancel!`:
|
18
|
+
```ruby
|
19
|
+
c = Sidekiq::Client.new
|
20
|
+
jid = c.push("class" => SomeJob, "args" => [123])
|
21
|
+
c.cancel!(jid) # => true
|
22
|
+
```
|
23
|
+
- Take over support for ActiveJob's `:sidekiq` adapter [#6430, fatkodima]
|
24
|
+
- Ensure CurrentAttributes are in scope when creating batch callbacks [#6455]
|
25
|
+
- Add `Sidekiq.gem_version` API.
|
26
|
+
- Update Ukranian translations
|
27
|
+
|
28
|
+
7.3.2
|
29
|
+
----------
|
30
|
+
|
31
|
+
- Adjust ActiveRecord batch iteration to restart an interrupted batch from the beginning.
|
32
|
+
Each batch should be processed as a single transaction in order to be idempotent. [#6405]
|
33
|
+
- Fix typo in Sidekiq::DeadSet#kill [#6397]
|
34
|
+
- Fix CSS issue with bottom bar in Web UI [#6414]
|
35
|
+
|
5
36
|
7.3.1
|
6
37
|
----------
|
7
38
|
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sidekiq
|
4
|
+
module ActiveJob
|
5
|
+
# @api private
|
6
|
+
class Wrapper
|
7
|
+
include Sidekiq::Job
|
8
|
+
|
9
|
+
def perform(job_data)
|
10
|
+
::ActiveJob::Base.execute(job_data.merge("provider_job_id" => jid))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ActiveJob
|
17
|
+
module QueueAdapters
|
18
|
+
# Explicitly remove the implementation existing in older rails'.
|
19
|
+
remove_const(:SidekiqAdapter) if defined?(:SidekiqAdapter)
|
20
|
+
|
21
|
+
# Sidekiq adapter for Active Job
|
22
|
+
#
|
23
|
+
# To use Sidekiq set the queue_adapter config to +:sidekiq+.
|
24
|
+
#
|
25
|
+
# Rails.application.config.active_job.queue_adapter = :sidekiq
|
26
|
+
class SidekiqAdapter
|
27
|
+
# Defines whether enqueuing should happen implicitly to after commit when called
|
28
|
+
# from inside a transaction.
|
29
|
+
# @api private
|
30
|
+
def enqueue_after_transaction_commit?
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
# @api private
|
35
|
+
def enqueue(job)
|
36
|
+
job.provider_job_id = JobWrapper.set(
|
37
|
+
wrapped: job.class,
|
38
|
+
queue: job.queue_name
|
39
|
+
).perform_async(job.serialize)
|
40
|
+
end
|
41
|
+
|
42
|
+
# @api private
|
43
|
+
def enqueue_at(job, timestamp)
|
44
|
+
job.provider_job_id = JobWrapper.set(
|
45
|
+
wrapped: job.class,
|
46
|
+
queue: job.queue_name
|
47
|
+
).perform_at(timestamp, job.serialize)
|
48
|
+
end
|
49
|
+
|
50
|
+
# @api private
|
51
|
+
def enqueue_all(jobs)
|
52
|
+
enqueued_count = 0
|
53
|
+
jobs.group_by(&:class).each do |job_class, same_class_jobs|
|
54
|
+
same_class_jobs.group_by(&:queue_name).each do |queue, same_class_and_queue_jobs|
|
55
|
+
immediate_jobs, scheduled_jobs = same_class_and_queue_jobs.partition { |job| job.scheduled_at.nil? }
|
56
|
+
|
57
|
+
if immediate_jobs.any?
|
58
|
+
jids = Sidekiq::Client.push_bulk(
|
59
|
+
"class" => JobWrapper,
|
60
|
+
"wrapped" => job_class,
|
61
|
+
"queue" => queue,
|
62
|
+
"args" => immediate_jobs.map { |job| [job.serialize] }
|
63
|
+
)
|
64
|
+
enqueued_count += jids.compact.size
|
65
|
+
end
|
66
|
+
|
67
|
+
if scheduled_jobs.any?
|
68
|
+
jids = Sidekiq::Client.push_bulk(
|
69
|
+
"class" => JobWrapper,
|
70
|
+
"wrapped" => job_class,
|
71
|
+
"queue" => queue,
|
72
|
+
"args" => scheduled_jobs.map { |job| [job.serialize] },
|
73
|
+
"at" => scheduled_jobs.map { |job| job.scheduled_at&.to_f }
|
74
|
+
)
|
75
|
+
enqueued_count += jids.compact.size
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
enqueued_count
|
80
|
+
end
|
81
|
+
|
82
|
+
# Defines a class alias for backwards compatibility with enqueued Active Job jobs.
|
83
|
+
# @api private
|
84
|
+
class JobWrapper < Sidekiq::ActiveJob::Wrapper
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/sidekiq/api.rb
CHANGED
@@ -373,7 +373,7 @@ module Sidekiq
|
|
373
373
|
def display_class
|
374
374
|
# Unwrap known wrappers so they show up in a human-friendly manner in the Web UI
|
375
375
|
@klass ||= self["display_class"] || begin
|
376
|
-
if klass == "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
|
376
|
+
if klass == "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper" || klass == "Sidekiq::ActiveJob::Wrapper"
|
377
377
|
job_class = @item["wrapped"] || args[0]
|
378
378
|
if job_class == "ActionMailer::DeliveryJob" || job_class == "ActionMailer::MailDeliveryJob"
|
379
379
|
# MailerClass#mailer_method
|
@@ -389,7 +389,7 @@ module Sidekiq
|
|
389
389
|
|
390
390
|
def display_args
|
391
391
|
# Unwrap known wrappers so they show up in a human-friendly manner in the Web UI
|
392
|
-
@display_args ||= if klass == "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
|
392
|
+
@display_args ||= if klass == "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper" || klass == "Sidekiq::ActiveJob::Wrapper"
|
393
393
|
job_args = self["wrapped"] ? deserialize_argument(args[0]["arguments"]) : []
|
394
394
|
if (self["wrapped"] || args[0]) == "ActionMailer::DeliveryJob"
|
395
395
|
# remove MailerClass, mailer_method and 'deliver_now'
|
@@ -813,8 +813,8 @@ module Sidekiq
|
|
813
813
|
|
814
814
|
# Add the given job to the Dead set.
|
815
815
|
# @param message [String] the job data as JSON
|
816
|
-
# @option opts
|
817
|
-
# @option opts
|
816
|
+
# @option opts [Boolean] :notify_failure (true) Whether death handlers should be called
|
817
|
+
# @option opts [Exception] :ex (RuntimeError) An exception to pass to the death handlers
|
818
818
|
def kill(message, opts = {})
|
819
819
|
now = Time.now.to_f
|
820
820
|
Sidekiq.redis do |conn|
|
@@ -828,7 +828,7 @@ module Sidekiq
|
|
828
828
|
if opts[:notify_failure] != false
|
829
829
|
job = Sidekiq.load_json(message)
|
830
830
|
if opts[:ex]
|
831
|
-
ex =
|
831
|
+
ex = opts[:ex]
|
832
832
|
else
|
833
833
|
ex = RuntimeError.new("Job killed by API")
|
834
834
|
ex.set_backtrace(caller)
|
data/lib/sidekiq/capsule.rb
CHANGED
@@ -40,9 +40,9 @@ module Sidekiq
|
|
40
40
|
|
41
41
|
def fetcher
|
42
42
|
@fetcher ||= begin
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
instance = (config[:fetch_class] || Sidekiq::BasicFetch).new(self)
|
44
|
+
instance.setup(config[:fetch_setup]) if instance.respond_to?(:setup)
|
45
|
+
instance
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
data/lib/sidekiq/client.rb
CHANGED
@@ -58,6 +58,23 @@ module Sidekiq
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
+
# Cancel the IterableJob with the given JID.
|
62
|
+
# **NB: Cancellation is asynchronous.** Iteration checks every
|
63
|
+
# five seconds so this will not immediately stop the given job.
|
64
|
+
def cancel!(jid)
|
65
|
+
key = "it-#{jid}"
|
66
|
+
_, result, _ = Sidekiq.redis do |c|
|
67
|
+
c.pipelined do |p|
|
68
|
+
p.hsetnx(key, "cancelled", Time.now.to_i)
|
69
|
+
p.hget(key, "cancelled")
|
70
|
+
p.expire(key, Sidekiq::Job::Iterable::STATE_TTL)
|
71
|
+
# TODO When Redis 7.2 is required
|
72
|
+
# p.expire(key, Sidekiq::Job::Iterable::STATE_TTL, "nx")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
result.to_i
|
76
|
+
end
|
77
|
+
|
61
78
|
##
|
62
79
|
# The main method used to push a job to Redis. Accepts a number of options:
|
63
80
|
#
|
data/lib/sidekiq/config.rb
CHANGED
@@ -185,7 +185,13 @@ module Sidekiq
|
|
185
185
|
|
186
186
|
# register global singletons which can be accessed elsewhere
|
187
187
|
def register(name, instance)
|
188
|
-
|
188
|
+
# logger.debug("register[#{name}] = #{instance}")
|
189
|
+
# Sidekiq Enterprise lazy registers a few services so we
|
190
|
+
# can't lock down this hash completely.
|
191
|
+
hash = @directory.dup
|
192
|
+
hash[name] = instance
|
193
|
+
@directory = hash.freeze
|
194
|
+
instance
|
189
195
|
end
|
190
196
|
|
191
197
|
# find a singleton
|
@@ -193,10 +199,16 @@ module Sidekiq
|
|
193
199
|
# JNDI is just a fancy name for a hash lookup
|
194
200
|
@directory.fetch(name) do |key|
|
195
201
|
return nil unless default_class
|
196
|
-
|
202
|
+
register(key, default_class.new(self))
|
197
203
|
end
|
198
204
|
end
|
199
205
|
|
206
|
+
def freeze!
|
207
|
+
@directory.freeze
|
208
|
+
@options.freeze
|
209
|
+
true
|
210
|
+
end
|
211
|
+
|
200
212
|
##
|
201
213
|
# Death handlers are called when all retries for a job have been exhausted and
|
202
214
|
# the job dies. It's the notification to your application
|
@@ -22,7 +22,7 @@ module Sidekiq
|
|
22
22
|
def batches
|
23
23
|
Enumerator.new(-> { @relation.count }) do |yielder|
|
24
24
|
@relation.find_in_batches(**@options, start: @cursor) do |batch|
|
25
|
-
yielder.yield(batch, batch.
|
25
|
+
yielder.yield(batch, batch.first.id)
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
@@ -35,8 +35,8 @@ module Sidekiq
|
|
35
35
|
options[:of] ||= options.delete(:batch_size)
|
36
36
|
|
37
37
|
@relation.in_batches(**options, start: @cursor) do |relation|
|
38
|
-
|
39
|
-
yielder.yield(relation,
|
38
|
+
first_record = relation.first
|
39
|
+
yielder.yield(relation, first_record.id)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
data/lib/sidekiq/job/iterable.rb
CHANGED
@@ -30,6 +30,40 @@ module Sidekiq
|
|
30
30
|
@_cursor = nil
|
31
31
|
@_start_time = nil
|
32
32
|
@_runtime = 0
|
33
|
+
@_args = nil
|
34
|
+
@_cancelled = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def arguments
|
38
|
+
@_args
|
39
|
+
end
|
40
|
+
|
41
|
+
# Three days is the longest period you generally need to wait for a retry to
|
42
|
+
# execute when using the default retry scheme. We don't want to "forget" the job
|
43
|
+
# is cancelled before it has a chance to execute and cancel itself.
|
44
|
+
CANCELLATION_PERIOD = (3 * 86_400).to_s
|
45
|
+
|
46
|
+
# Set a flag in Redis to mark this job as cancelled.
|
47
|
+
# Cancellation is asynchronous and is checked at the start of iteration
|
48
|
+
# and every 5 seconds thereafter as part of the recurring state flush.
|
49
|
+
def cancel!
|
50
|
+
return @_cancelled if cancelled?
|
51
|
+
|
52
|
+
key = "it-#{jid}"
|
53
|
+
_, result, _ = Sidekiq.redis do |c|
|
54
|
+
c.pipelined do |p|
|
55
|
+
p.hsetnx(key, "cancelled", Time.now.to_i)
|
56
|
+
p.hget(key, "cancelled")
|
57
|
+
# TODO When Redis 7.2 is required
|
58
|
+
# p.expire(key, Sidekiq::Job::Iterable::STATE_TTL, "nx")
|
59
|
+
p.expire(key, Sidekiq::Job::Iterable::STATE_TTL)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
@_cancelled = result.to_i
|
63
|
+
end
|
64
|
+
|
65
|
+
def cancelled?
|
66
|
+
@_cancelled
|
33
67
|
end
|
34
68
|
|
35
69
|
# A hook to override that will be called when the job starts iterating.
|
@@ -91,13 +125,14 @@ module Sidekiq
|
|
91
125
|
end
|
92
126
|
|
93
127
|
# @api private
|
94
|
-
def perform(*
|
128
|
+
def perform(*args)
|
129
|
+
@_args = args.dup.freeze
|
95
130
|
fetch_previous_iteration_state
|
96
131
|
|
97
132
|
@_executions += 1
|
98
133
|
@_start_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
99
134
|
|
100
|
-
enumerator = build_enumerator(*
|
135
|
+
enumerator = build_enumerator(*args, cursor: @_cursor)
|
101
136
|
unless enumerator
|
102
137
|
logger.info("'#build_enumerator' returned nil, skipping the job.")
|
103
138
|
return
|
@@ -112,7 +147,7 @@ module Sidekiq
|
|
112
147
|
end
|
113
148
|
|
114
149
|
completed = catch(:abort) do
|
115
|
-
iterate_with_enumerator(enumerator,
|
150
|
+
iterate_with_enumerator(enumerator, args)
|
116
151
|
end
|
117
152
|
|
118
153
|
on_stop
|
@@ -128,6 +163,10 @@ module Sidekiq
|
|
128
163
|
|
129
164
|
private
|
130
165
|
|
166
|
+
def is_cancelled?
|
167
|
+
@_cancelled = Sidekiq.redis { |c| c.hget("it-#{jid}", "cancelled") }
|
168
|
+
end
|
169
|
+
|
131
170
|
def fetch_previous_iteration_state
|
132
171
|
state = Sidekiq.redis { |conn| conn.hgetall(iteration_key) }
|
133
172
|
|
@@ -144,6 +183,12 @@ module Sidekiq
|
|
144
183
|
STATE_TTL = 30 * 24 * 60 * 60 # one month
|
145
184
|
|
146
185
|
def iterate_with_enumerator(enumerator, arguments)
|
186
|
+
if is_cancelled?
|
187
|
+
logger.info { "Job cancelled" }
|
188
|
+
return true
|
189
|
+
end
|
190
|
+
|
191
|
+
time_limit = Sidekiq.default_configuration[:timeout]
|
147
192
|
found_record = false
|
148
193
|
state_flushed_at = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
149
194
|
|
@@ -153,14 +198,21 @@ module Sidekiq
|
|
153
198
|
|
154
199
|
is_interrupted = interrupted?
|
155
200
|
if ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - state_flushed_at >= STATE_FLUSH_INTERVAL || is_interrupted
|
156
|
-
flush_state
|
201
|
+
_, _, cancelled = flush_state
|
157
202
|
state_flushed_at = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
203
|
+
if cancelled == 1
|
204
|
+
@_cancelled = true
|
205
|
+
logger.info { "Job cancelled" }
|
206
|
+
return true
|
207
|
+
end
|
158
208
|
end
|
159
209
|
|
160
210
|
return false if is_interrupted
|
161
211
|
|
162
|
-
|
163
|
-
|
212
|
+
verify_iteration_time(time_limit, object) do
|
213
|
+
around_iteration do
|
214
|
+
each_iteration(object, *arguments)
|
215
|
+
end
|
164
216
|
end
|
165
217
|
end
|
166
218
|
|
@@ -170,6 +222,16 @@ module Sidekiq
|
|
170
222
|
@_runtime += (::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - @_start_time)
|
171
223
|
end
|
172
224
|
|
225
|
+
def verify_iteration_time(time_limit, object)
|
226
|
+
start = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
227
|
+
yield
|
228
|
+
finish = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
229
|
+
total = finish - start
|
230
|
+
if total > time_limit
|
231
|
+
logger.warn { "Iteration took longer (%.2f) than Sidekiq's shutdown timeout (%d) when processing `%s`. This can lead to job processing problems during deploys" % [total, time_limit, object] }
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
173
235
|
def reenqueue_iteration_job
|
174
236
|
flush_state
|
175
237
|
logger.debug { "Interrupting job (cursor=#{@_cursor.inspect})" }
|
@@ -204,6 +266,7 @@ module Sidekiq
|
|
204
266
|
conn.multi do |pipe|
|
205
267
|
pipe.hset(key, state)
|
206
268
|
pipe.expire(key, STATE_TTL)
|
269
|
+
pipe.hget(key, "cancelled")
|
207
270
|
end
|
208
271
|
end
|
209
272
|
end
|
@@ -1,12 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "concurrent"
|
4
|
-
|
5
3
|
module Sidekiq
|
6
4
|
module Metrics
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
class Counter
|
6
|
+
def initialize
|
7
|
+
@value = 0
|
8
|
+
@lock = Mutex.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def increment
|
12
|
+
@lock.synchronize { @value += 1 }
|
13
|
+
end
|
14
|
+
|
15
|
+
def value
|
16
|
+
@lock.synchronize { @value }
|
17
|
+
end
|
18
|
+
end
|
10
19
|
|
11
20
|
# Implements space-efficient but statistically useful histogram storage.
|
12
21
|
# A precise time histogram stores every time. Instead we break times into a set of
|
data/lib/sidekiq/processor.rb
CHANGED
@@ -138,11 +138,11 @@ module Sidekiq
|
|
138
138
|
# Effectively this block denotes a "unit of work" to Rails.
|
139
139
|
@reloader.call do
|
140
140
|
klass = Object.const_get(job_hash["class"])
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
@retrier.local(
|
145
|
-
yield
|
141
|
+
instance = klass.new
|
142
|
+
instance.jid = job_hash["jid"]
|
143
|
+
instance._context = self
|
144
|
+
@retrier.local(instance, jobstr, queue) do
|
145
|
+
yield instance
|
146
146
|
end
|
147
147
|
end
|
148
148
|
end
|
@@ -180,9 +180,9 @@ module Sidekiq
|
|
180
180
|
ack = false
|
181
181
|
Thread.handle_interrupt(IGNORE_SHUTDOWN_INTERRUPTS) do
|
182
182
|
Thread.handle_interrupt(ALLOW_SHUTDOWN_INTERRUPTS) do
|
183
|
-
dispatch(job_hash, queue, jobstr) do |
|
184
|
-
config.server_middleware.invoke(
|
185
|
-
execute_job(
|
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
186
|
end
|
187
187
|
end
|
188
188
|
ack = true
|
@@ -216,8 +216,8 @@ module Sidekiq
|
|
216
216
|
end
|
217
217
|
end
|
218
218
|
|
219
|
-
def execute_job(
|
220
|
-
|
219
|
+
def execute_job(instance, cloned_args)
|
220
|
+
instance.perform(*cloned_args)
|
221
221
|
end
|
222
222
|
|
223
223
|
# Ruby doesn't provide atomic counters out of the box so we'll
|
data/lib/sidekiq/rails.rb
CHANGED
data/lib/sidekiq/testing.rb
CHANGED
@@ -283,11 +283,11 @@ module Sidekiq
|
|
283
283
|
end
|
284
284
|
|
285
285
|
def process_job(job)
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
Sidekiq::Testing.server_middleware.invoke(
|
290
|
-
execute_job(
|
286
|
+
instance = new
|
287
|
+
instance.jid = job["jid"]
|
288
|
+
instance.bid = job["bid"] if instance.respond_to?(:bid=)
|
289
|
+
Sidekiq::Testing.server_middleware.invoke(instance, job, job["queue"]) do
|
290
|
+
execute_job(instance, job["args"])
|
291
291
|
end
|
292
292
|
end
|
293
293
|
|
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/web/action.rb
CHANGED
@@ -48,8 +48,12 @@ module Sidekiq
|
|
48
48
|
if content.is_a? Symbol
|
49
49
|
unless respond_to?(:"_erb_#{content}")
|
50
50
|
views = options[:views] || Web.settings.views
|
51
|
-
|
52
|
-
|
51
|
+
filename = "#{views}/#{content}.erb"
|
52
|
+
src = ERB.new(File.read(filename)).src
|
53
|
+
|
54
|
+
# Need to use lineno less by 1 because erb generates a
|
55
|
+
# comment before the source code.
|
56
|
+
WebAction.class_eval <<-RUBY, filename, -1 # standard:disable Style/EvalWithLocation
|
53
57
|
def _erb_#{content}
|
54
58
|
#{src}
|
55
59
|
end
|
@@ -331,12 +331,10 @@ module Sidekiq
|
|
331
331
|
########
|
332
332
|
# Filtering
|
333
333
|
|
334
|
-
get "/filter/metrics" do
|
335
|
-
redirect "#{root_path}metrics"
|
336
|
-
end
|
337
|
-
|
338
|
-
post "/filter/metrics" do
|
334
|
+
route :get, :post, "/filter/metrics" do
|
339
335
|
x = params[:substr]
|
336
|
+
return redirect "#{root_path}metrics" unless x && x != ""
|
337
|
+
|
340
338
|
q = Sidekiq::Metrics::Query.new
|
341
339
|
@period = h((params[:period] || "")[0..1])
|
342
340
|
@periods = METRICS_PERIODS
|
@@ -346,15 +344,7 @@ module Sidekiq
|
|
346
344
|
erb :metrics
|
347
345
|
end
|
348
346
|
|
349
|
-
get "/filter/retries" do
|
350
|
-
x = params[:substr]
|
351
|
-
return redirect "#{root_path}retries" unless x && x != ""
|
352
|
-
|
353
|
-
@retries = search(Sidekiq::RetrySet.new, params[:substr])
|
354
|
-
erb :retries
|
355
|
-
end
|
356
|
-
|
357
|
-
post "/filter/retries" do
|
347
|
+
route :get, :post, "/filter/retries" do
|
358
348
|
x = params[:substr]
|
359
349
|
return redirect "#{root_path}retries" unless x && x != ""
|
360
350
|
|
@@ -362,15 +352,7 @@ module Sidekiq
|
|
362
352
|
erb :retries
|
363
353
|
end
|
364
354
|
|
365
|
-
get "/filter/scheduled" do
|
366
|
-
x = params[:substr]
|
367
|
-
return redirect "#{root_path}scheduled" unless x && x != ""
|
368
|
-
|
369
|
-
@scheduled = search(Sidekiq::ScheduledSet.new, params[:substr])
|
370
|
-
erb :scheduled
|
371
|
-
end
|
372
|
-
|
373
|
-
post "/filter/scheduled" do
|
355
|
+
route :get, :post, "/filter/scheduled" do
|
374
356
|
x = params[:substr]
|
375
357
|
return redirect "#{root_path}scheduled" unless x && x != ""
|
376
358
|
|
@@ -378,15 +360,7 @@ module Sidekiq
|
|
378
360
|
erb :scheduled
|
379
361
|
end
|
380
362
|
|
381
|
-
get "/filter/dead" do
|
382
|
-
x = params[:substr]
|
383
|
-
return redirect "#{root_path}morgue" unless x && x != ""
|
384
|
-
|
385
|
-
@dead = search(Sidekiq::DeadSet.new, params[:substr])
|
386
|
-
erb :morgue
|
387
|
-
end
|
388
|
-
|
389
|
-
post "/filter/dead" do
|
363
|
+
route :get, :post, "/filter/dead" do
|
390
364
|
x = params[:substr]
|
391
365
|
return redirect "#{root_path}morgue" unless x && x != ""
|
392
366
|
|
data/lib/sidekiq/web/router.rb
CHANGED
@@ -39,10 +39,13 @@ module Sidekiq
|
|
39
39
|
route(DELETE, path, &block)
|
40
40
|
end
|
41
41
|
|
42
|
-
def route(
|
42
|
+
def route(*methods, path, &block)
|
43
43
|
@routes ||= {GET => [], POST => [], PUT => [], PATCH => [], DELETE => [], HEAD => []}
|
44
44
|
|
45
|
-
|
45
|
+
methods.each do |method|
|
46
|
+
method = method.to_s.upcase
|
47
|
+
@routes[method] << WebRoute.new(method, path, block)
|
48
|
+
end
|
46
49
|
end
|
47
50
|
|
48
51
|
def match(env)
|
data/lib/sidekiq/web.rb
CHANGED
@@ -213,7 +213,7 @@ module Sidekiq
|
|
213
213
|
Sidekiq::WebApplication.helpers WebHelpers
|
214
214
|
Sidekiq::WebApplication.helpers Sidekiq::Paginator
|
215
215
|
|
216
|
-
Sidekiq::WebAction.class_eval <<-RUBY,
|
216
|
+
Sidekiq::WebAction.class_eval <<-RUBY, Web::LAYOUT, -1 # standard:disable Style/EvalWithLocation
|
217
217
|
def _render
|
218
218
|
#{ERB.new(File.read(Web::LAYOUT)).src}
|
219
219
|
end
|
data/lib/sidekiq.rb
CHANGED
@@ -102,18 +102,19 @@ module Sidekiq
|
|
102
102
|
def self.freeze!
|
103
103
|
@frozen = true
|
104
104
|
@config_blocks = nil
|
105
|
+
default_configuration.freeze!
|
105
106
|
end
|
106
107
|
|
107
108
|
# Creates a Sidekiq::Config instance that is more tuned for embedding
|
108
109
|
# within an arbitrary Ruby process. Notably it reduces concurrency by
|
109
110
|
# default so there is less contention for CPU time with other threads.
|
110
111
|
#
|
111
|
-
#
|
112
|
+
# instance = Sidekiq.configure_embed do |config|
|
112
113
|
# config.queues = %w[critical default low]
|
113
114
|
# end
|
114
|
-
#
|
115
|
+
# instance.run
|
115
116
|
# sleep 10
|
116
|
-
#
|
117
|
+
# instance.stop
|
117
118
|
#
|
118
119
|
# NB: it is really easy to overload a Ruby process with threads due to the GIL.
|
119
120
|
# I do not recommend setting concurrency higher than 2-3.
|
data/sidekiq.gemspec
CHANGED
@@ -634,12 +634,8 @@ div.interval-slider input {
|
|
634
634
|
.container {
|
635
635
|
padding: 0;
|
636
636
|
}
|
637
|
-
.navbar-fixed-bottom {
|
638
|
-
position: relative;
|
639
|
-
top: auto;
|
640
|
-
}
|
641
637
|
@media (max-width: 767px) {
|
642
|
-
.navbar-fixed-top {
|
638
|
+
.navbar-fixed-top, .navbar-fixed-bottom {
|
643
639
|
position: relative;
|
644
640
|
top: auto;
|
645
641
|
}
|
@@ -652,18 +648,18 @@ div.interval-slider input {
|
|
652
648
|
|
653
649
|
@media (min-width: 768px) {
|
654
650
|
.redis-url {
|
655
|
-
max-width:
|
651
|
+
max-width: 160px;
|
656
652
|
}
|
657
653
|
}
|
658
654
|
|
659
655
|
@media (min-width: 992px) {
|
660
656
|
.redis-url {
|
661
|
-
max-width:
|
657
|
+
max-width: 380px;
|
662
658
|
}
|
663
659
|
}
|
664
660
|
@media (min-width: 1200px) {
|
665
661
|
.redis-url {
|
666
|
-
max-width:
|
662
|
+
max-width: 580px;
|
667
663
|
}
|
668
664
|
}
|
669
665
|
|
data/web/locales/en.yml
CHANGED
data/web/locales/fr.yml
CHANGED
data/web/locales/gd.yml
CHANGED
data/web/locales/ja.yml
CHANGED
data/web/locales/pt-br.yml
CHANGED
@@ -7,7 +7,6 @@
|
|
7
7
|
Arguments: Argumentos
|
8
8
|
AvgExecutionTime: Tempo médio de execução
|
9
9
|
BackToApp: De volta ao aplicativo
|
10
|
-
Bucket: Bucket
|
11
10
|
Busy: Ocupados
|
12
11
|
Class: Classe
|
13
12
|
Connections: Conexões
|
@@ -93,4 +92,4 @@
|
|
93
92
|
Utilization: Utilização
|
94
93
|
Version: Versão
|
95
94
|
When: Quando
|
96
|
-
Worker: Trabalhador
|
95
|
+
Worker: Trabalhador
|
data/web/locales/tr.yml
CHANGED
data/web/locales/uk.yml
CHANGED
@@ -6,31 +6,39 @@ uk:
|
|
6
6
|
AreYouSureDeleteJob: Ви впевнені у тому, що хочете видалити задачу?
|
7
7
|
AreYouSureDeleteQueue: Ви впевнені у тому, що хочете видалити чергу %{queue}?
|
8
8
|
Arguments: Аргументи
|
9
|
+
BackToApp: Назад
|
9
10
|
Busy: Зайнятих
|
10
11
|
Class: Клас
|
11
12
|
Connections: З'єднань
|
13
|
+
CreatedAt: Створено
|
12
14
|
CurrentMessagesInQueue: Поточні задачі у черзі <span class='title'>%{queue}</span>
|
13
15
|
Dashboard: Панель керування
|
14
16
|
Dead: Вбитих
|
15
17
|
DeadJobs: Вбиті задачі
|
16
18
|
Delete: Видалити
|
17
19
|
DeleteAll: Видалити усі
|
20
|
+
Deploy: Деплой
|
18
21
|
Enqueued: У черзі
|
19
22
|
Error: Помилка
|
20
23
|
ErrorBacktrace: Трасування помилки
|
21
24
|
ErrorClass: Клас помилки
|
22
25
|
ErrorMessage: Повідомлення про помилку
|
26
|
+
ExecutionTime: Час виконання
|
23
27
|
Extras: Додатково
|
24
28
|
Failed: Невдалих
|
25
29
|
Failures: Невдачі
|
30
|
+
Failure: Невдача
|
26
31
|
GoBack: ← Назад
|
27
32
|
History: Історія
|
28
33
|
Job: Задача
|
29
34
|
Jobs: Задачі
|
30
|
-
Kill:
|
35
|
+
Kill: Вбити
|
36
|
+
KillAll: Вбити все
|
31
37
|
LastRetry: Остання спроба
|
38
|
+
Latency: Затримка
|
32
39
|
LivePoll: Постійне опитування
|
33
40
|
MemoryUsage: Використання пам'яті
|
41
|
+
Name: Назва
|
34
42
|
Namespace: Простір імен
|
35
43
|
NextRetry: Наступна спроба
|
36
44
|
NoDeadJobsFound: Вбитих задач не знайдено
|
@@ -40,10 +48,12 @@ uk:
|
|
40
48
|
OneMonth: 1 місяць
|
41
49
|
OneWeek: 1 тиждень
|
42
50
|
OriginallyFailed: Перша невдала спроба
|
51
|
+
Pause: Призупинити
|
43
52
|
Paused: Призупинено
|
44
53
|
PeakMemoryUsage: Максимальне використання пам'яті
|
45
54
|
Plugins: Плагіни
|
46
55
|
PollingInterval: Інтервал опитування
|
56
|
+
Process: Процес
|
47
57
|
Processed: Опрацьовано
|
48
58
|
Processes: Процеси
|
49
59
|
Queue: Черга
|
@@ -57,6 +67,7 @@ uk:
|
|
57
67
|
RetryNow: Повторити зараз
|
58
68
|
Scheduled: Заплановано
|
59
69
|
ScheduledJobs: Заплановані задачі
|
70
|
+
Seconds: Секунди
|
60
71
|
ShowAll: Відобразити усі
|
61
72
|
SixMonths: 6 місяців
|
62
73
|
Size: Розмір
|
@@ -65,13 +76,25 @@ uk:
|
|
65
76
|
Stop: Зупинити
|
66
77
|
StopAll: Зупинити усі
|
67
78
|
StopPolling: Зупинити опитування
|
79
|
+
Success: Успіх
|
80
|
+
Summary: Підсумок
|
68
81
|
Thread: Потік
|
69
82
|
Threads: Потоки
|
70
83
|
ThreeMonths: 3 місяці
|
71
84
|
Time: Час
|
85
|
+
Unpause: Відновити
|
72
86
|
Uptime: Днів безперебійної роботи
|
87
|
+
Utilization: Утилізація
|
73
88
|
Version: Версія
|
74
89
|
When: Коли
|
75
90
|
Worker: Обробник
|
76
91
|
active: активний
|
77
92
|
idle: незайнятий
|
93
|
+
Metrics: Метрики
|
94
|
+
NoDataFound: Даних не знайдено
|
95
|
+
TotalExecutionTime: Загальний час виконання
|
96
|
+
AvgExecutionTime: Середній час виконання
|
97
|
+
Context: Контекст
|
98
|
+
NoJobMetricsFound: Недавніх метрик задачі не знайдено
|
99
|
+
Filter: Фільтр
|
100
|
+
AnyJobContent: Будь-який атрибут задачі
|
data/web/locales/zh-cn.yml
CHANGED
data/web/locales/zh-tw.yml
CHANGED
data/web/views/metrics.erb
CHANGED
@@ -54,8 +54,8 @@
|
|
54
54
|
<th><%= t('Name') %></th>
|
55
55
|
<th><%= t('Success') %></th>
|
56
56
|
<th><%= t('Failure') %></th>
|
57
|
-
<th><%= t('TotalExecutionTime') %> (Seconds)</th>
|
58
|
-
<th><%= t('AvgExecutionTime') %> (Seconds)</th>
|
57
|
+
<th><%= t('TotalExecutionTime') %> (<%= t('Seconds') %>)</th>
|
58
|
+
<th><%= t('AvgExecutionTime') %> (<%= t('Seconds') %>)</th>
|
59
59
|
</tr>
|
60
60
|
<% if job_results.any? %>
|
61
61
|
<% job_results.each_with_index do |(kls, jr), i| %>
|
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.3.
|
4
|
+
version: 7.3.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: 2024-
|
11
|
+
date: 2024-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis-client
|
@@ -52,20 +52,6 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 2.2.4
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: concurrent-ruby
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "<"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '2'
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "<"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '2'
|
69
55
|
- !ruby/object:Gem::Dependency
|
70
56
|
name: logger
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -96,6 +82,7 @@ files:
|
|
96
82
|
- bin/sidekiq
|
97
83
|
- bin/sidekiqload
|
98
84
|
- bin/sidekiqmon
|
85
|
+
- lib/active_job/queue_adapters/sidekiq_adapter.rb
|
99
86
|
- lib/generators/sidekiq/job_generator.rb
|
100
87
|
- lib/generators/sidekiq/templates/job.rb.erb
|
101
88
|
- lib/generators/sidekiq/templates/job_spec.rb.erb
|