sidekiq 8.0.6 → 8.0.8

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: d76e142e5c120dc7d714ae218813bc6d3488064c291a407f0fbddc3b65b03d77
4
- data.tar.gz: db1326f0b7553125f67a9667811cc32e7768343fe2684d3aec2adef107e4e586
3
+ metadata.gz: 3a1e8c90888b4135f21e4dfef66fd9ad9ac8c72ab267599a8452f4bd172234a2
4
+ data.tar.gz: fa83e70c818fc3b25441e946c1a093a2d9a5f4515ee2bd88522cbafcb8097973
5
5
  SHA512:
6
- metadata.gz: 99e54bdfb34e9fe257b740917cd675d959eac98566a15d53f65638095d7fe6da2966efbfd9d958c9c580034b4af49adb9cd3c94cd189b39fb7360a021f471714
7
- data.tar.gz: afedc02f36f45de8e65fe58d897ae11f7aaa9f105f9b87c2f47b01dbcc501087d5c9d2dcf3c436bc3427ec801371c43a8f7c92741e30d87cc91fad9dc34ba429
6
+ metadata.gz: 0ea8ac9585538723d941af6ce9150933669705cf1e3459dcea8989d073d234c4e233e74314a5a682e3111e1290a69671051e847b5ee97970c1edd08293e14bbc
7
+ data.tar.gz: 0b253cd035132f786613fbb97440f5d16f48717aedaa7f50865e0e261ce0fc17b64885bea3cdeb5aabe72258c06ed013891d83655bdcf842fc1a261d1b0aa985
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
+ 8.0.8
6
+ ----------
7
+
8
+ - Allow an optional global iteration max runtime. After executing for this length of time,
9
+ Sidekiq will re-queue the job to continue execution at a later time [#6819, fatkodima]
10
+ ```ruby
11
+ Sidekiq.configure_server do |cfg|
12
+ cfg[:max_iteration_runtime] = 600 # ten minutes
13
+ end
14
+ ```
15
+ - Add `discarded_at` attribute when discarding a job so death handlers can distinguish between
16
+ a job which was killed and one that was discarded. [#6820, gstokkink]
17
+ - `perform_bulk` now accepts an `:at` array of times to schedule each job at the corresponding time.
18
+ `perform_bulk(args: [[1], [2]], at: [Time.now, Time.now + 1])` [#6790, fatkodima]
19
+ - `perform_bulk` now accepts a `:spread_interval` value to schedule jobs over
20
+ the next N seconds. `perform_bulk(..., spread_interval: 60)` [#6792, fatkodima]
21
+ - Fix unintended display of flash messages in the Web UI due to session key collision
22
+ - Add support for lazy load hooks [#6825]
23
+
24
+ 8.0.7
25
+ ----------
26
+
27
+ - The `:discard` option for `sidekiq_retries_exhausted` and `sidekiq_retry_in`
28
+ now calls death handlers, otherwise it could break other Sidekiq
29
+ functionality. [#6741]
30
+ - Provide a Plain log formatter which does not colorize output [#6778]
31
+ - Job iteration now exposes `current_object` for easy access within the `around_iteration` callback [#6774]
32
+ - Fix JS race condition which could skip confirmation dialogs when Live Polling [#6768]
33
+ - Fix edge case which could lose CurrentAttributes [#6767]
34
+ - Update UK locale [#6776]
35
+
5
36
  8.0.6
6
37
  ----------
7
38
 
data/lib/sidekiq/api.rb CHANGED
@@ -1168,7 +1168,6 @@ module Sidekiq
1168
1168
  # # thread_id is a unique identifier per thread
1169
1169
  # # work is a `Sidekiq::Work` instance that has the following accessor methods.
1170
1170
  # # [work.queue, work.run_at, work.payload]
1171
- # # run_at is an epoch Integer.
1172
1171
  # end
1173
1172
  #
1174
1173
  class WorkSet
@@ -1322,3 +1321,5 @@ module Sidekiq
1322
1321
  end
1323
1322
  end
1324
1323
  end
1324
+
1325
+ Sidekiq.loader.run_load_hooks(:api)
@@ -117,6 +117,9 @@ module Sidekiq
117
117
  # larger than 1000 but YMMV based on network quality, size of job args, etc.
118
118
  # A large number of jobs can cause a bit of Redis command processing latency.
119
119
  #
120
+ # Accepts an additional `:spread_interval` option (in seconds) to randomly spread
121
+ # the jobs schedule times over the specified interval.
122
+ #
120
123
  # Takes the same arguments as #push except that args is expected to be
121
124
  # an Array of Arrays. All other keys are duplicated for each job. Each job
122
125
  # is run through the client middleware pipeline and each job gets its own Job ID
@@ -131,13 +134,24 @@ module Sidekiq
131
134
  def push_bulk(items)
132
135
  batch_size = items.delete(:batch_size) || items.delete("batch_size") || 1_000
133
136
  args = items["args"]
134
- at = items.delete("at")
137
+ at = items.delete("at") || items.delete(:at)
135
138
  raise ArgumentError, "Job 'at' must be a Numeric or an Array of Numeric timestamps" if at && (Array(at).empty? || !Array(at).all? { |entry| entry.is_a?(Numeric) })
136
139
  raise ArgumentError, "Job 'at' Array must have same size as 'args' Array" if at.is_a?(Array) && at.size != args.size
137
140
 
138
141
  jid = items.delete("jid")
139
142
  raise ArgumentError, "Explicitly passing 'jid' when pushing more than one job is not supported" if jid && args.size > 1
140
143
 
144
+ spread_interval = items.delete(:spread_interval) || items.delete("spread_interval")
145
+ raise ArgumentError, "Jobs 'spread_interval' must be a positive Numeric" if spread_interval && (!spread_interval.is_a?(Numeric) || spread_interval <= 0)
146
+ raise ArgumentError, "Only one of 'at' or 'spread_interval' can be provided" if at && spread_interval
147
+
148
+ if !at && spread_interval
149
+ # Do not use spread interval smaller than pooling interval.
150
+ spread_interval = [spread_interval, 5].max
151
+ now = Time.now.to_f
152
+ at = args.map { now + rand * spread_interval }
153
+ end
154
+
141
155
  normed = normalize_item(items)
142
156
  slice_index = 0
143
157
  result = args.each_slice(batch_size).flat_map do |slice|
@@ -19,7 +19,8 @@ module Sidekiq
19
19
  DEFAULT_THREAD_PRIORITY = -1
20
20
 
21
21
  ##
22
- # Sidekiq::Component assumes a config instance is available at @config
22
+ # Sidekiq::Component provides a set of utility methods depending only
23
+ # on Sidekiq::Config. It assumes a config instance is available at @config.
23
24
  module Component # :nodoc:
24
25
  attr_reader :config
25
26
 
@@ -17,10 +17,9 @@ module Sidekiq
17
17
  poll_interval_average: nil,
18
18
  average_scheduled_poll_interval: 5,
19
19
  on_complex_arguments: :raise,
20
- iteration: {
21
- max_job_runtime: nil,
22
- retry_backoff: 0
23
- },
20
+ # if the Iterable job runs longer than this value (in seconds), then the job
21
+ # will be interrupted after the current iteration and re-enqueued at the back of the queue
22
+ max_iteration_runtime: nil,
24
23
  error_handlers: [],
25
24
  death_handlers: [],
26
25
  lifecycle_events: {
@@ -32,8 +32,14 @@ module Sidekiq
32
32
  @_runtime = 0
33
33
  @_args = nil
34
34
  @_cancelled = nil
35
+ @current_object = nil
35
36
  end
36
37
 
38
+ # Access to the current object while iterating.
39
+ # This value is not reset so the latest element is
40
+ # explicitly available to cleanup/complete callbacks.
41
+ attr_reader :current_object
42
+
37
43
  def arguments
38
44
  @_args
39
45
  end
@@ -137,7 +143,7 @@ module Sidekiq
137
143
  fetch_previous_iteration_state
138
144
 
139
145
  @_executions += 1
140
- @_start_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
146
+ @_start_time = mono_now
141
147
 
142
148
  enumerator = build_enumerator(*args, cursor: @_cursor)
143
149
  unless enumerator
@@ -198,16 +204,17 @@ module Sidekiq
198
204
 
199
205
  time_limit = Sidekiq.default_configuration[:timeout]
200
206
  found_record = false
201
- state_flushed_at = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
207
+ state_flushed_at = mono_now
202
208
 
203
209
  enumerator.each do |object, cursor|
204
210
  found_record = true
205
211
  @_cursor = cursor
212
+ @current_object = object
206
213
 
207
- is_interrupted = interrupted?
208
- if ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - state_flushed_at >= STATE_FLUSH_INTERVAL || is_interrupted
214
+ interrupt_job = interrupted? || should_interrupt?
215
+ if mono_now - state_flushed_at >= STATE_FLUSH_INTERVAL || interrupt_job
209
216
  _, _, cancelled = flush_state
210
- state_flushed_at = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
217
+ state_flushed_at = mono_now
211
218
  if cancelled
212
219
  @_cancelled = true
213
220
  on_cancel
@@ -216,9 +223,9 @@ module Sidekiq
216
223
  end
217
224
  end
218
225
 
219
- return false if is_interrupted
226
+ return false if interrupt_job
220
227
 
221
- verify_iteration_time(time_limit, object) do
228
+ verify_iteration_time(time_limit) do
222
229
  around_iteration do
223
230
  each_iteration(object, *arguments)
224
231
  rescue Exception
@@ -231,16 +238,16 @@ module Sidekiq
231
238
  logger.debug("Enumerator found nothing to iterate!") unless found_record
232
239
  true
233
240
  ensure
234
- @_runtime += (::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - @_start_time)
241
+ @_runtime += (mono_now - @_start_time)
235
242
  end
236
243
 
237
- def verify_iteration_time(time_limit, object)
238
- start = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
244
+ def verify_iteration_time(time_limit)
245
+ start = mono_now
239
246
  yield
240
- finish = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
247
+ finish = mono_now
241
248
  total = finish - start
242
249
  if total > time_limit
243
- 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] }
250
+ logger.warn { "Iteration took longer (%.2f) than Sidekiq's shutdown timeout (%d). This can lead to job processing problems during deploys" % [total, time_limit] }
244
251
  end
245
252
  end
246
253
 
@@ -266,6 +273,11 @@ module Sidekiq
266
273
  end
267
274
  end
268
275
 
276
+ def should_interrupt?
277
+ max_iteration_runtime = Sidekiq.default_configuration[:max_iteration_runtime]
278
+ max_iteration_runtime && (mono_now - @_start_time > max_iteration_runtime)
279
+ end
280
+
269
281
  def flush_state
270
282
  key = iteration_key
271
283
  state = {
@@ -301,6 +313,10 @@ module Sidekiq
301
313
  raise "Unexpected thrown value: #{completed.inspect}"
302
314
  end
303
315
  end
316
+
317
+ def mono_now
318
+ ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
319
+ end
304
320
  end
305
321
  end
306
322
  end
data/lib/sidekiq/job.rb CHANGED
@@ -248,9 +248,9 @@ module Sidekiq
248
248
  end
249
249
  alias_method :perform_sync, :perform_inline
250
250
 
251
- def perform_bulk(args, batch_size: 1_000)
251
+ def perform_bulk(args, **options)
252
252
  client = @klass.build_client
253
- client.push_bulk(@opts.merge("class" => @klass, "args" => args, :batch_size => batch_size))
253
+ client.push_bulk(@opts.merge({"class" => @klass, "args" => args}, options))
254
254
  end
255
255
 
256
256
  # +interval+ must be a timestamp, numeric or something that acts
@@ -27,7 +27,7 @@ module Sidekiq
27
27
  # attribute to expose the underlying thing.
28
28
  h = {
29
29
  jid: job_hash["jid"],
30
- class: job_hash["display_class"] || job_hash["wrapped"] || job_hash["class"]
30
+ class: job_hash["wrapped"] || job_hash["class"]
31
31
  }
32
32
  h[:bid] = job_hash["bid"] if job_hash.has_key?("bid")
33
33
  h[:tags] = job_hash["tags"] if job_hash.has_key?("tags")
@@ -186,7 +186,9 @@ module Sidekiq
186
186
  strategy, delay = delay_for(jobinst, count, exception, msg)
187
187
  case strategy
188
188
  when :discard
189
- return # poof!
189
+ msg["discarded_at"] = now_ms
190
+
191
+ return run_death_handlers(msg, exception)
190
192
  when :kill
191
193
  return retries_exhausted(jobinst, msg, exception)
192
194
  end
@@ -255,13 +257,22 @@ module Sidekiq
255
257
  handle_exception(e, {context: "Error calling retries_exhausted", job: msg})
256
258
  end
257
259
 
258
- return if rv == :discard # poof!
259
- send_to_morgue(msg) unless msg["dead"] == false
260
+ discarded = msg["dead"] == false || rv == :discard
261
+
262
+ if discarded
263
+ msg["discarded_at"] = now_ms
264
+ else
265
+ send_to_morgue(msg)
266
+ end
267
+
268
+ run_death_handlers(msg, exception)
269
+ end
260
270
 
271
+ def run_death_handlers(job, exception)
261
272
  @capsule.config.death_handlers.each do |handler|
262
- handler.call(msg, exception)
273
+ handler.call(job, exception)
263
274
  rescue => e
264
- handle_exception(e, {context: "Error calling death handler", job: msg})
275
+ handle_exception(e, {context: "Error calling death handler", job: job})
265
276
  end
266
277
  end
267
278
 
@@ -0,0 +1,57 @@
1
+ module Sidekiq
2
+ require "sidekiq/component"
3
+
4
+ class Loader
5
+ include Sidekiq::Component
6
+
7
+ def initialize(cfg = Sidekiq.default_configuration)
8
+ @config = cfg
9
+ @load_hooks = Hash.new { |h, k| h[k] = [] }
10
+ @loaded = Set.new
11
+ @lock = Mutex.new
12
+ end
13
+
14
+ # Declares a block that will be executed when a Sidekiq component is fully
15
+ # loaded. If the component has already loaded, the block is executed
16
+ # immediately.
17
+ #
18
+ # Sidekiq.loader.on_load(:api) do
19
+ # # extend the sidekiq API
20
+ # end
21
+ #
22
+ def on_load(name, &block)
23
+ # we don't want to hold the lock while calling the block
24
+ to_run = nil
25
+
26
+ @lock.synchronize do
27
+ if @loaded.include?(name)
28
+ to_run = block
29
+ else
30
+ @load_hooks[name] << block
31
+ end
32
+ end
33
+
34
+ to_run&.call
35
+ nil
36
+ end
37
+
38
+ # Executes all blocks registered to +name+ via on_load.
39
+ #
40
+ # Sidekiq.loader.run_load_hooks(:api)
41
+ #
42
+ # In the case of the above example, it will execute all hooks registered for +:api+.
43
+ #
44
+ def run_load_hooks(name)
45
+ hks = @lock.synchronize do
46
+ @loaded << name
47
+ @load_hooks.delete(name)
48
+ end
49
+
50
+ hks&.each do |blk|
51
+ blk.call
52
+ rescue => ex
53
+ handle_exception(ex, hook: name)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -24,14 +24,15 @@ module Sidekiq
24
24
 
25
25
  class Logger < ::Logger
26
26
  module Formatters
27
- COLORS = {
28
- "DEBUG" => "\e[1;32mDEBUG\e[0m", # green
29
- "INFO" => "\e[1;34mINFO \e[0m", # blue
30
- "WARN" => "\e[1;33mWARN \e[0m", # yellow
31
- "ERROR" => "\e[1;31mERROR\e[0m", # red
32
- "FATAL" => "\e[1;35mFATAL\e[0m" # pink
33
- }
34
27
  class Base < ::Logger::Formatter
28
+ COLORS = {
29
+ "DEBUG" => "\e[1;32mDEBUG\e[0m", # green
30
+ "INFO" => "\e[1;34mINFO \e[0m", # blue
31
+ "WARN" => "\e[1;33mWARN \e[0m", # yellow
32
+ "ERROR" => "\e[1;31mERROR\e[0m", # red
33
+ "FATAL" => "\e[1;35mFATAL\e[0m" # pink
34
+ }
35
+
35
36
  def tid
36
37
  Thread.current["sidekiq_tid"] ||= (Thread.current.object_id ^ ::Process.pid).to_s(36)
37
38
  end
@@ -50,13 +51,19 @@ module Sidekiq
50
51
 
51
52
  class Pretty < Base
52
53
  def call(severity, time, program_name, message)
53
- "#{Formatters::COLORS[severity]} #{time.utc.iso8601(3)} pid=#{::Process.pid} tid=#{tid}#{format_context}: #{message}\n"
54
+ "#{COLORS[severity]} #{time.utc.iso8601(3)} pid=#{::Process.pid} tid=#{tid}#{format_context}: #{message}\n"
55
+ end
56
+ end
57
+
58
+ class Plain < Base
59
+ def call(severity, time, program_name, message)
60
+ "#{severity} #{time.utc.iso8601(3)} pid=#{::Process.pid} tid=#{tid}#{format_context}: #{message}\n"
54
61
  end
55
62
  end
56
63
 
57
64
  class WithoutTimestamp < Pretty
58
65
  def call(severity, time, program_name, message)
59
- "#{Formatters::COLORS[severity]} pid=#{::Process.pid} tid=#{tid} #{format_context}: #{message}\n"
66
+ "#{COLORS[severity]} pid=#{::Process.pid} tid=#{tid}#{format_context}: #{message}\n"
60
67
  end
61
68
  end
62
69
 
@@ -50,7 +50,7 @@ module Sidekiq
50
50
  @cattrs = cattrs
51
51
  end
52
52
 
53
- def call(_, job, _, &block)
53
+ def call(_, job, *, &block)
54
54
  klass_attrs = {}
55
55
 
56
56
  @cattrs.each do |(key, strklass)|
@@ -93,6 +93,7 @@ module Sidekiq
93
93
  def persist(klass_or_array, config = Sidekiq.default_configuration)
94
94
  cattrs = build_cattrs_hash(klass_or_array)
95
95
 
96
+ config.client_middleware.prepend Load, cattrs
96
97
  config.client_middleware.add Save, cattrs
97
98
  config.server_middleware.prepend Load, cattrs
98
99
  end
data/lib/sidekiq/rails.rb CHANGED
@@ -48,8 +48,10 @@ module Sidekiq
48
48
  unless ::Rails.logger == config.logger || ::ActiveSupport::Logger.logger_outputs_to?(::Rails.logger, $stdout)
49
49
  if ::Rails.logger.respond_to?(:broadcast_to)
50
50
  ::Rails.logger.broadcast_to(config.logger)
51
- else
51
+ elsif ::ActiveSupport::Logger.respond_to?(:broadcast)
52
52
  ::Rails.logger.extend(::ActiveSupport::Logger.broadcast(config.logger))
53
+ else
54
+ ::Rails.logger = ::ActiveSupport::BroadcastLogger.new(::Rails.logger, config.logger)
53
55
  end
54
56
  end
55
57
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sidekiq
4
- VERSION = "8.0.6"
4
+ VERSION = "8.0.8"
5
5
  MAJOR = 8
6
6
 
7
7
  def self.gem_version
@@ -102,15 +102,15 @@ module Sidekiq
102
102
  def flash
103
103
  msg = yield
104
104
  logger.info msg
105
- session[:flash] = msg
105
+ session[:skq_flash] = msg
106
106
  end
107
107
 
108
108
  def flash?
109
- session&.[](:flash)
109
+ session&.[](:skq_flash)
110
110
  end
111
111
 
112
112
  def get_flash
113
- @flash ||= session.delete(:flash)
113
+ @flash ||= session.delete(:skq_flash)
114
114
  end
115
115
 
116
116
  def erb(content, options = {})
data/lib/sidekiq.rb CHANGED
@@ -29,6 +29,7 @@ end
29
29
 
30
30
  require "sidekiq/config"
31
31
  require "sidekiq/logger"
32
+ require "sidekiq/loader"
32
33
  require "sidekiq/client"
33
34
  require "sidekiq/transaction_aware_client"
34
35
  require "sidekiq/job"
@@ -94,6 +95,10 @@ module Sidekiq
94
95
  default_configuration.logger
95
96
  end
96
97
 
98
+ def self.loader
99
+ @loader ||= Loader.new
100
+ end
101
+
97
102
  def self.configure_server(&block)
98
103
  (@config_blocks ||= []) << block
99
104
  yield default_configuration if server?
File without changes
File without changes
@@ -18,15 +18,6 @@ function addListeners() {
18
18
  })
19
19
  });
20
20
 
21
- document.querySelectorAll("input[data-confirm]").forEach(node => {
22
- node.addEventListener("click", event => {
23
- if (!window.confirm(node.getAttribute("data-confirm"))) {
24
- event.preventDefault();
25
- event.stopPropagation();
26
- }
27
- })
28
- })
29
-
30
21
  document.querySelectorAll("[data-toggle]").forEach(node => {
31
22
  node.addEventListener("click", addDataToggleListeners)
32
23
  })
@@ -67,7 +58,7 @@ function addPollingListeners(_event) {
67
58
 
68
59
  function addDataToggleListeners(event) {
69
60
  var source = event.target || event.srcElement;
70
- var targName = source.getAttribute("data-toggle");
61
+ var targName = source.dataset.toggle;
71
62
  var full = document.getElementById(targName);
72
63
  full.classList.toggle("is-open");
73
64
  }
@@ -90,7 +81,7 @@ function addShiftClickListeners() {
90
81
  }
91
82
 
92
83
  function updateFuzzyTimes() {
93
- var locale = document.body.getAttribute("data-locale");
84
+ var locale = document.body.dataset.locale;
94
85
  var parts = locale.split('-');
95
86
  if (typeof parts[1] !== 'undefined') {
96
87
  parts[1] = parts[1].toUpperCase();
@@ -105,7 +96,7 @@ function updateFuzzyTimes() {
105
96
  function updateNumbers() {
106
97
  document.querySelectorAll("[data-nwp]").forEach(node => {
107
98
  let number = parseFloat(node.textContent);
108
- let precision = parseInt(node.dataset["nwp"] || 0);
99
+ let precision = parseInt(node.dataset.nwp || 0);
109
100
  if (typeof number === "number") {
110
101
  let formatted = number.toLocaleString(undefined, {
111
102
  minimumFractionDigits: precision,
@@ -178,4 +169,20 @@ function updateLocale(event) {
178
169
 
179
170
  function updateProgressBars() {
180
171
  document.querySelectorAll('.progress-bar').forEach(bar => { bar.style.width = bar.dataset.width + "%"})
181
- }
172
+ }
173
+
174
+ function handleConfirmDialog (event) {
175
+ const target = event.target
176
+
177
+ if (target.localName !== "input") { return }
178
+ const confirmMessage = target.dataset.confirm
179
+
180
+ if (confirmMessage === undefined) { return }
181
+
182
+ if (!window.confirm(confirmMessage)) {
183
+ event.preventDefault()
184
+ event.stopPropagation()
185
+ }
186
+ }
187
+
188
+ document.addEventListener("click", handleConfirmDialog)
@@ -29,8 +29,6 @@
29
29
 
30
30
  *, *::before, *::after { box-sizing: border-box; }
31
31
 
32
- ::selection { background: var(--color-selected); }
33
-
34
32
  :focus-visible {
35
33
  outline: 1px solid oklch(from var(--color-primary) l c h / 50%);
36
34
  }
@@ -567,7 +565,6 @@ body > footer .nav {
567
565
  --color-border: oklch(25% 0.01 256);
568
566
  --color-input-border: oklch(31% 0.01 256);
569
567
  --color-selected: oklch(27% 0.01 256);
570
- --color-selected-text: oklch(55% 0.11 45);
571
568
  --color-table-bg-alt: oklch(24% 0.01 256);
572
569
  --color-shadow: oklch(9% 0.01 256 / 10%);
573
570
  --color-text: oklch(75% 0.01 256);
@@ -616,10 +613,6 @@ body > footer .nav {
616
613
  .label-info { background: var(--color-info); }
617
614
  .label-danger { background: var(--color-danger); }
618
615
  .label-warning { background: var(--color-warning); }
619
-
620
- td.box::selection {
621
- background-color: var(--color-selected-text);
622
- }
623
616
  }
624
617
 
625
618
  @media (max-width: 800px) { :root { --font-size: 14px; } }
data/web/locales/uk.yml CHANGED
@@ -14,8 +14,8 @@ uk:
14
14
  CreatedAt: Створено
15
15
  CurrentMessagesInQueue: Поточні задачі у черзі <span class='title'>%{queue}</span>
16
16
  Dashboard: Панель керування
17
- Dead: Вбитих
18
- DeadJobs: Вбиті задачі
17
+ Dead: Зупинених
18
+ DeadJobs: Зупинені задачі
19
19
  Delete: Видалити
20
20
  DeleteAll: Видалити усі
21
21
  Deploy: Деплой
@@ -33,8 +33,8 @@ uk:
33
33
  History: Історія
34
34
  Job: Задача
35
35
  Jobs: Задачі
36
- Kill: Вбити
37
- KillAll: Вбити все
36
+ Kill: Зупинити
37
+ KillAll: Зупинити все
38
38
  LastRetry: Остання спроба
39
39
  Latency: Затримка
40
40
  LivePoll: Постійне опитування
@@ -42,7 +42,7 @@ uk:
42
42
  Name: Назва
43
43
  Namespace: Простір імен
44
44
  NextRetry: Наступна спроба
45
- NoDeadJobsFound: Вбитих задач не знайдено
45
+ NoDeadJobsFound: Зупинених задач не знайдено
46
46
  NoRetriesFound: Спроб не знайдено
47
47
  NoScheduledFound: Запланованих задач не знайдено
48
48
  NotYetEnqueued: Ще не в черзі
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.6
4
+ version: 8.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Perham
@@ -122,6 +122,7 @@ files:
122
122
  - lib/sidekiq/job_retry.rb
123
123
  - lib/sidekiq/job_util.rb
124
124
  - lib/sidekiq/launcher.rb
125
+ - lib/sidekiq/loader.rb
125
126
  - lib/sidekiq/logger.rb
126
127
  - lib/sidekiq/manager.rb
127
128
  - lib/sidekiq/metrics/query.rb