sidekiq 7.3.2 → 7.3.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ce4653de61d5b923ce7556490e95cf6918dd1c94340417ec4093f11cc8ceda39
4
- data.tar.gz: e9faa23d4535a5b647c5dc86c28ce64317ea964f44faa9141b5a883f77b80dcd
3
+ metadata.gz: f278eab88087d46198fc13a2f5019f1d7e399810ecfebeba5044ff9bfd25e271
4
+ data.tar.gz: fb790ae54375a60b30b9eaf6676291a8f42c5a17a9f9487c6f018447810bb46f
5
5
  SHA512:
6
- metadata.gz: 5fa259f415261689936b4f03f179198ea6849fbe63b932b5836fa800714055ce574a80a56462355a92d125440362957ebf02e5bafbde55fe8211805c80573ae5
7
- data.tar.gz: 0aaf341ae13c377e6f944344e0feef246e3450ae9eb0d74fcbf8e932e9c9fcf0d8f0dd56ce374064d4f51c4d99f4c306560c3283db27f70ae6aa5af346d83ec3
6
+ metadata.gz: 676ca234e7ce2218a72266f793a686c4fe5c944535ad5a76d7b7c263190a1eccb9341c06fbff0ab2e11acd4875c5dee74d959b9d1019687904b8cb53a84a6267
7
+ data.tar.gz: ab7f1f5acbfc9064d93d8881354bd5a572a96f45f125c1074cf50212f23a1d60df8ac196843a45963064009f41e074eb322a50acb3680fd62ee727fcae36c14f
data/Changes.md CHANGED
@@ -2,12 +2,35 @@
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
+
5
28
  7.3.2
6
29
  ----------
7
30
 
8
31
  - Adjust ActiveRecord batch iteration to restart an interrupted batch from the beginning.
9
32
  Each batch should be processed as a single transaction in order to be idempotent. [#6405]
10
- - Fix typo in S::DeadSet#kill [#6397]
33
+ - Fix typo in Sidekiq::DeadSet#kill [#6397]
11
34
  - Fix CSS issue with bottom bar in Web UI [#6414]
12
35
 
13
36
  7.3.1
@@ -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'
@@ -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
@@ -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.2"
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
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.2
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-09-04 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