sidekiq 7.3.1 → 7.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9f5b830734b904971e3969d347d0447564003a2afc743d681df9c2285e5e8681
4
- data.tar.gz: 462e557d3093492eed4f4fb234f6015e52bb024e44398e617e5d8b6baebdf1ac
3
+ metadata.gz: f278eab88087d46198fc13a2f5019f1d7e399810ecfebeba5044ff9bfd25e271
4
+ data.tar.gz: fb790ae54375a60b30b9eaf6676291a8f42c5a17a9f9487c6f018447810bb46f
5
5
  SHA512:
6
- metadata.gz: d2b3bac182022693b4de09fe220fdae54a2e9e1ac68f0ce5d12d8e5b08f55d873cd62d7de4b40f0170e918f79c389501d29cc57ea691e78c98d9bb9ba4d4b709
7
- data.tar.gz: 57d2312adca3de676e9c5fb30cd5ee8ed44270a0e0f460b2720d26cf5771c3144a7815db7694563d4d1d34185d6c3382448cdfa750a5a72449ffdcba1c889ab1
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 :notify_failure [Boolean] (true) Whether death handlers should be called
817
- # @option opts :ex [Exception] (RuntimeError) An exception to pass to the death handlers
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 = opt[:ex]
831
+ ex = opts[:ex]
832
832
  else
833
833
  ex = RuntimeError.new("Job killed by API")
834
834
  ex.set_backtrace(caller)
@@ -40,9 +40,9 @@ module Sidekiq
40
40
 
41
41
  def fetcher
42
42
  @fetcher ||= begin
43
- inst = (config[:fetch_class] || Sidekiq::BasicFetch).new(self)
44
- inst.setup(config[:fetch_setup]) if inst.respond_to?(:setup)
45
- inst
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
 
@@ -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
  #
@@ -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
- @directory[name] = instance
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
- @directory[key] = default_class.new(self)
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.last.id)
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
- last_record = relation.last
39
- yielder.yield(relation, last_record.id)
38
+ first_record = relation.first
39
+ yielder.yield(relation, first_record.id)
40
40
  end
41
41
  end
42
42
  end
@@ -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(*arguments)
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(*arguments, cursor: @_cursor)
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, arguments)
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
- around_iteration do
163
- each_iteration(object, *arguments)
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
- # This is the only dependency on concurrent-ruby in Sidekiq but it's
8
- # mandatory for thread-safety until MRI supports atomic operations on values.
9
- Counter = ::Concurrent::AtomicFixnum
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
@@ -88,7 +88,7 @@ module Sidekiq
88
88
  cattrs = build_cattrs_hash(klass_or_array)
89
89
 
90
90
  config.client_middleware.add Save, cattrs
91
- config.server_middleware.add Load, cattrs
91
+ config.server_middleware.prepend Load, cattrs
92
92
  end
93
93
 
94
94
  private
@@ -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
- inst = klass.new
142
- inst.jid = job_hash["jid"]
143
- inst._context = self
144
- @retrier.local(inst, jobstr, queue) do
145
- yield inst
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 |inst|
184
- config.server_middleware.invoke(inst, job_hash, queue) do
185
- execute_job(inst, job_hash["args"])
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(inst, cloned_args)
220
- inst.perform(*cloned_args)
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
@@ -3,6 +3,12 @@
3
3
  require "sidekiq/job"
4
4
  require "rails"
5
5
 
6
+ begin
7
+ require "active_job"
8
+ require "active_job/queue_adapters/sidekiq_adapter"
9
+ rescue LoadError
10
+ end
11
+
6
12
  module Sidekiq
7
13
  class Rails < ::Rails::Engine
8
14
  class Reloader
@@ -283,11 +283,11 @@ module Sidekiq
283
283
  end
284
284
 
285
285
  def process_job(job)
286
- inst = new
287
- inst.jid = job["jid"]
288
- inst.bid = job["bid"] if inst.respond_to?(:bid=)
289
- Sidekiq::Testing.server_middleware.invoke(inst, job, job["queue"]) do
290
- execute_job(inst, job["args"])
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
 
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sidekiq
4
- VERSION = "7.3.1"
4
+ VERSION = "7.3.3"
5
5
  MAJOR = 7
6
+
7
+ def self.gem_version
8
+ Gem::Version.new(VERSION)
9
+ end
6
10
  end
@@ -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
- src = ERB.new(File.read("#{views}/#{content}.erb")).src
52
- WebAction.class_eval <<-RUBY, __FILE__, __LINE__ + 1
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
 
@@ -39,10 +39,13 @@ module Sidekiq
39
39
  route(DELETE, path, &block)
40
40
  end
41
41
 
42
- def route(method, path, &block)
42
+ def route(*methods, path, &block)
43
43
  @routes ||= {GET => [], POST => [], PUT => [], PATCH => [], DELETE => [], HEAD => []}
44
44
 
45
- @routes[method] << WebRoute.new(method, path, block)
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, __FILE__, __LINE__ + 1
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
- # inst = Sidekiq.configure_embed do |config|
112
+ # instance = Sidekiq.configure_embed do |config|
112
113
  # config.queues = %w[critical default low]
113
114
  # end
114
- # inst.run
115
+ # instance.run
115
116
  # sleep 10
116
- # inst.stop
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
@@ -26,6 +26,5 @@ Gem::Specification.new do |gem|
26
26
  gem.add_dependency "redis-client", ">= 0.22.2"
27
27
  gem.add_dependency "connection_pool", ">= 2.3.0"
28
28
  gem.add_dependency "rack", ">= 2.2.4"
29
- gem.add_dependency "concurrent-ruby", "< 2"
30
29
  gem.add_dependency "logger"
31
30
  end
@@ -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: 250px;
651
+ max-width: 160px;
656
652
  }
657
653
  }
658
654
 
659
655
  @media (min-width: 992px) {
660
656
  .redis-url {
661
- max-width: 490px;
657
+ max-width: 380px;
662
658
  }
663
659
  }
664
660
  @media (min-width: 1200px) {
665
661
  .redis-url {
666
- max-width: 600px;
662
+ max-width: 580px;
667
663
  }
668
664
  }
669
665
 
data/web/locales/en.yml CHANGED
@@ -95,7 +95,6 @@ en:
95
95
  TotalExecutionTime: Total Execution Time
96
96
  AvgExecutionTime: Average Execution Time
97
97
  Context: Context
98
- Bucket: Bucket
99
98
  NoJobMetricsFound: No recent job metrics were found
100
99
  Filter: Filter
101
100
  AnyJobContent: Any job content
data/web/locales/fr.yml CHANGED
@@ -95,5 +95,4 @@ fr:
95
95
  TotalExecutionTime: Temps d'exécution total
96
96
  AvgExecutionTime: Temps d'exécution moyen
97
97
  Context: Contexte
98
- Bucket: Bucket
99
98
  NoJobMetricsFound: Aucune statistique de tâche récente n'a été trouvée
data/web/locales/gd.yml CHANGED
@@ -95,5 +95,4 @@ gd:
95
95
  TotalExecutionTime: Ùine iomlan nan gnìomhan
96
96
  AvgExecutionTime: Ùine cuibheasach nan gnìomhan
97
97
  Context: Co-theacsa
98
- Bucket: Bucaid
99
98
  NoJobMetricsFound: Cha deach meatraigeachd o chionn goirid air obair a lorg
data/web/locales/ja.yml CHANGED
@@ -87,5 +87,4 @@ ja:
87
87
  TotalExecutionTime: 合計実行時間
88
88
  AvgExecutionTime: 平均実行時間
89
89
  Context: コンテキスト
90
- Bucket: バケット
91
90
  NoJobMetricsFound: 直近のジョブメトリクスが見つかりませんでした
@@ -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
@@ -95,7 +95,6 @@ tr:
95
95
  TotalExecutionTime: Toplam Yürütme Süresi
96
96
  AvgExecutionTime: Ortalama Yürütme Süresi
97
97
  Context: Bağlam
98
- Bucket: Kova
99
98
  NoJobMetricsFound: Son iş metrikleri bulunamadı
100
99
  Filter: Filtre
101
100
  AnyJobContent: Herhangi bir iş içeriği
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: Будь-який атрибут задачі
@@ -89,7 +89,6 @@ zh-cn: # <---- change this to your locale code
89
89
  TotalExecutionTime: 总执行时间
90
90
  AvgExecutionTime: 平均执行时间
91
91
  Context: 上下文
92
- Bucket: 桶
93
92
  NoJobMetricsFound: 无任务相关指标数据
94
93
  Success: 成功
95
94
  Failure: 失败
@@ -98,5 +98,4 @@ zh-tw: # <---- change this to your locale code
98
98
  TotalExecutionTime: 總執行時間
99
99
  AvgExecutionTime: 平均執行時間
100
100
  Context: 上下文
101
- Bucket: 桶
102
101
  NoJobMetricsFound: 找無工作相關計量資料
@@ -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.1
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-08-15 00:00:00.000000000 Z
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