sidekiq 7.0.2 → 7.0.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sidekiq might be problematic. Click here for more details.

@@ -21,12 +21,16 @@ module Sidekiq
21
21
  attr_reader :name
22
22
  attr_reader :queues
23
23
  attr_accessor :concurrency
24
+ attr_reader :mode
25
+ attr_reader :weights
24
26
 
25
27
  def initialize(name, config)
26
28
  @name = name
27
29
  @config = config
28
30
  @queues = ["default"]
31
+ @weights = {"default" => 0}
29
32
  @concurrency = config[:concurrency]
33
+ @mode = :strict
30
34
  end
31
35
 
32
36
  def fetcher
@@ -41,15 +45,28 @@ module Sidekiq
41
45
  fetcher&.bulk_requeue([])
42
46
  end
43
47
 
48
+ # Sidekiq checks queues in three modes:
49
+ # - :strict - all queues have 0 weight and are checked strictly in order
50
+ # - :weighted - queues have arbitrary weight between 1 and N
51
+ # - :random - all queues have weight of 1
44
52
  def queues=(val)
53
+ @weights = {}
45
54
  @queues = Array(val).each_with_object([]) do |qstr, memo|
46
55
  arr = qstr
47
56
  arr = qstr.split(",") if qstr.is_a?(String)
48
57
  name, weight = arr
58
+ @weights[name] = weight.to_i
49
59
  [weight.to_i, 1].max.times do
50
60
  memo << name
51
61
  end
52
62
  end
63
+ @mode = if @weights.values.all?(&:zero?)
64
+ :strict
65
+ elsif @weights.values.all? { |x| x == 1 }
66
+ :random
67
+ else
68
+ :weighted
69
+ end
53
70
  end
54
71
 
55
72
  # Allow the middleware to be different per-capsule.
data/lib/sidekiq/cli.rb CHANGED
@@ -77,13 +77,14 @@ module Sidekiq # :nodoc:
77
77
  raise "You are connecting to Redis #{ver}, Sidekiq requires Redis 6.2.0 or greater" if ver < Gem::Version.new("6.2.0")
78
78
 
79
79
  maxmemory_policy = info["maxmemory_policy"]
80
- if maxmemory_policy != "noeviction"
80
+ if maxmemory_policy != "noeviction" && maxmemory_policy != ""
81
+ # Redis Enterprise Cloud returns "" for their policy 😳
81
82
  logger.warn <<~EOM
82
83
 
83
84
 
84
85
  WARNING: Your Redis instance will evict Sidekiq data under heavy load.
85
86
  The 'noeviction' maxmemory policy is recommended (current policy: '#{maxmemory_policy}').
86
- See: https://github.com/mperham/sidekiq/wiki/Using-Redis#memory
87
+ See: https://github.com/sidekiq/sidekiq/wiki/Using-Redis#memory
87
88
 
88
89
  EOM
89
90
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sidekiq
2
4
  ##
3
5
  # Sidekiq::Component assumes a config instance is available at @config
@@ -129,7 +129,7 @@ module Sidekiq
129
129
  def new_redis_pool(size, name = "unset")
130
130
  # connection pool is lazy, it will not create connections unless you actually need them
131
131
  # so don't be skimpy!
132
- RedisConnection.create(@redis_config.merge(size: size, logger: logger, pool_name: name))
132
+ RedisConnection.create({size: size, logger: logger, pool_name: name}.merge(@redis_config))
133
133
  end
134
134
 
135
135
  def redis_info
@@ -49,7 +49,7 @@ module Sidekiq
49
49
 
50
50
  WARNING: Your Redis instance will evict Sidekiq data under heavy load.
51
51
  The 'noeviction' maxmemory policy is recommended (current policy: '#{maxmemory_policy}').
52
- See: https://github.com/mperham/sidekiq/wiki/Using-Redis#memory
52
+ See: https://github.com/sidekiq/sidekiq/wiki/Using-Redis#memory
53
53
 
54
54
  EOM
55
55
  end
data/lib/sidekiq/fetch.rb CHANGED
@@ -30,11 +30,9 @@ module Sidekiq # :nodoc:
30
30
  def initialize(cap)
31
31
  raise ArgumentError, "missing queue list" unless cap.queues
32
32
  @config = cap
33
- @strictly_ordered_queues = (config.queues.size == config.queues.uniq.size)
33
+ @strictly_ordered_queues = cap.mode == :strict
34
34
  @queues = config.queues.map { |q| "queue:#{q}" }
35
- if @strictly_ordered_queues
36
- @queues.uniq!
37
- end
35
+ @queues.uniq! if @strictly_ordered_queues
38
36
  end
39
37
 
40
38
  def retrieve_work
@@ -49,7 +49,7 @@ module Sidekiq
49
49
  # The default number of retries is 25 which works out to about 3 weeks
50
50
  # You can change the default maximum number of retries in your initializer:
51
51
  #
52
- # Sidekiq.options[:max_retries] = 7
52
+ # Sidekiq.default_configuration[:max_retries] = 7
53
53
  #
54
54
  # or limit the number of retries for a particular job and send retries to
55
55
  # a low priority queue with:
@@ -17,18 +17,24 @@ module Sidekiq
17
17
 
18
18
  def verify_json(item)
19
19
  job_class = item["wrapped"] || item["class"]
20
- if Sidekiq::Config::DEFAULTS[:on_complex_arguments] == :raise
21
- msg = <<~EOM
22
- Job arguments to #{job_class} must be native JSON types, see https://github.com/mperham/sidekiq/wiki/Best-Practices.
23
- To disable this error, add `Sidekiq.strict_args!(false)` to your initializer.
24
- EOM
25
- raise(ArgumentError, msg) unless json_safe?(item)
26
- elsif Sidekiq::Config::DEFAULTS[:on_complex_arguments] == :warn
27
- warn <<~EOM unless json_safe?(item)
28
- Job arguments to #{job_class} do not serialize to JSON safely. This will raise an error in
29
- Sidekiq 7.0. See https://github.com/mperham/sidekiq/wiki/Best-Practices or raise an error today
30
- by calling `Sidekiq.strict_args!` during Sidekiq initialization.
31
- EOM
20
+ args = item["args"]
21
+ mode = Sidekiq::Config::DEFAULTS[:on_complex_arguments]
22
+
23
+ if mode == :raise || mode == :warn
24
+ unless json_safe?(args)
25
+ unsafe_item = json_unsafe_item(args)
26
+ msg = <<~EOM
27
+ Job arguments to #{job_class} must be native JSON types, but #{unsafe_item.inspect} is a #{unsafe_item.class}.
28
+ See https://github.com/sidekiq/sidekiq/wiki/Best-Practices.
29
+ To disable this error, add `Sidekiq.strict_args!(false)` to your initializer.
30
+ EOM
31
+
32
+ if mode == :raise
33
+ raise(ArgumentError, msg)
34
+ else
35
+ warn(msg)
36
+ end
37
+ end
32
38
  end
33
39
  end
34
40
 
@@ -64,8 +70,50 @@ module Sidekiq
64
70
 
65
71
  private
66
72
 
73
+ RECURSIVE_JSON_SAFE = {
74
+ Integer => ->(val) { true },
75
+ Float => ->(val) { true },
76
+ TrueClass => ->(val) { true },
77
+ FalseClass => ->(val) { true },
78
+ NilClass => ->(val) { true },
79
+ String => ->(val) { true },
80
+ Array => ->(val) {
81
+ val.all? { |e| RECURSIVE_JSON_SAFE[e.class].call(e) }
82
+ },
83
+ Hash => ->(val) {
84
+ val.all? { |k, v| String === k && RECURSIVE_JSON_SAFE[v.class].call(v) }
85
+ }
86
+ }
87
+
88
+ RECURSIVE_JSON_SAFE.default = ->(_val) { false }
89
+ RECURSIVE_JSON_SAFE.compare_by_identity
90
+ private_constant :RECURSIVE_JSON_SAFE
91
+
67
92
  def json_safe?(item)
68
- JSON.parse(JSON.dump(item["args"])) == item["args"]
93
+ RECURSIVE_JSON_SAFE[item.class].call(item)
94
+ end
95
+
96
+ def json_unsafe_item(item)
97
+ case item
98
+ when String, Integer, Float, TrueClass, FalseClass, NilClass
99
+ nil
100
+ when Array
101
+ item.each do |e|
102
+ unsafe_item = json_unsafe_item(e)
103
+ return unsafe_item unless unsafe_item.nil?
104
+ end
105
+ nil
106
+ when Hash
107
+ item.each do |k, v|
108
+ return k unless String === k
109
+
110
+ unsafe_item = json_unsafe_item(v)
111
+ return unsafe_item unless unsafe_item.nil?
112
+ end
113
+ nil
114
+ else
115
+ item
116
+ end
69
117
  end
70
118
  end
71
119
  end
@@ -161,7 +161,7 @@ module Sidekiq
161
161
  fails = procd = 0
162
162
  kb = memory_usage(::Process.pid)
163
163
 
164
- _, exists, _, _, msg = redis { |conn|
164
+ _, exists, _, _, signal = redis { |conn|
165
165
  conn.multi { |transaction|
166
166
  transaction.sadd("processes", [key])
167
167
  transaction.exists(key)
@@ -180,9 +180,7 @@ module Sidekiq
180
180
  fire_event(:heartbeat) unless exists > 0
181
181
  fire_event(:beat, oneshot: false)
182
182
 
183
- return unless msg
184
-
185
- ::Process.kill(msg, ::Process.pid)
183
+ ::Process.kill(signal, ::Process.pid) if signal && !@embedded
186
184
  rescue => e
187
185
  # ignore all redis/network issues
188
186
  logger.error("heartbeat: #{e}")
@@ -216,7 +214,7 @@ module Sidekiq
216
214
  Last RTT readings were #{RTT_READINGS.buffer.inspect}, ideally these should be < 1000.
217
215
  Ensure Redis is running in the same AZ or datacenter as Sidekiq.
218
216
  If these values are close to 100,000, that means your Sidekiq process may be
219
- CPU-saturated; reduce your concurrency and/or see https://github.com/mperham/sidekiq/discussions/5039
217
+ CPU-saturated; reduce your concurrency and/or see https://github.com/sidekiq/sidekiq/discussions/5039
220
218
  EOM
221
219
  RTT_READINGS.reset
222
220
  end
@@ -251,13 +249,18 @@ module Sidekiq
251
249
  "tag" => @config[:tag] || "",
252
250
  "concurrency" => @config.total_concurrency,
253
251
  "queues" => @config.capsules.values.flat_map { |cap| cap.queues }.uniq,
254
- "weights" => @config.capsules.values.flat_map { |cap| cap.queues }.tally,
252
+ "weights" => to_weights,
255
253
  "labels" => @config[:labels].to_a,
256
254
  "identity" => identity,
257
- "version" => Sidekiq::VERSION
255
+ "version" => Sidekiq::VERSION,
256
+ "embedded" => @embedded
258
257
  }
259
258
  end
260
259
 
260
+ def to_weights
261
+ @config.capsules.values.map(&:weights)
262
+ end
263
+
261
264
  def to_json
262
265
  # this data changes infrequently so dump it to a string
263
266
  # now so we don't need to dump it every heartbeat.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "time"
2
4
  require "sidekiq"
3
5
  require "sidekiq/metrics/shared"
@@ -166,23 +166,26 @@ module Sidekiq
166
166
 
167
167
  # Used by Sidekiq to execute the middleware at runtime
168
168
  # @api private
169
- def invoke(*args)
169
+ def invoke(*args, &block)
170
170
  return yield if empty?
171
171
 
172
172
  chain = retrieve
173
- traverse_chain = proc do
174
- if chain.empty?
175
- yield
176
- else
177
- chain.shift.call(*args, &traverse_chain)
173
+ traverse(chain, 0, args, &block)
174
+ end
175
+
176
+ private
177
+
178
+ def traverse(chain, index, args, &block)
179
+ if index >= chain.size
180
+ yield
181
+ else
182
+ chain[index].call(*args) do
183
+ traverse(chain, index + 1, args, &block)
178
184
  end
179
185
  end
180
- traverse_chain.call
181
186
  end
182
187
  end
183
188
 
184
- private
185
-
186
189
  # Represents each link in the middleware chain
187
190
  # @api private
188
191
  class Entry
@@ -22,13 +22,11 @@ module Sidekiq
22
22
  end
23
23
 
24
24
  def call(_, job, _, _)
25
- attrs = @strklass.constantize.attributes
26
- if attrs.any?
27
- if job.has_key?("cattr")
28
- job["cattr"].merge!(attrs)
29
- else
30
- job["cattr"] = attrs
31
- end
25
+ if !job.has_key?("cattr")
26
+ attrs = @strklass.constantize.attributes
27
+ # Retries can push the job N times, we don't
28
+ # want retries to reset cattr. #5692, #5090
29
+ job["cattr"] = attrs if attrs.any?
32
30
  end
33
31
  yield
34
32
  end
@@ -16,8 +16,6 @@ class Sidekiq::Monitor
16
16
  return
17
17
  end
18
18
  send(section)
19
- rescue => e
20
- abort "Couldn't get status: #{e}"
21
19
  end
22
20
 
23
21
  def all
@@ -58,7 +56,7 @@ class Sidekiq::Monitor
58
56
  # {"default" => 1, "critical" => 10}
59
57
  queues =
60
58
  if process["weights"]
61
- process["weights"].sort_by { |queue| queue[0] }.map { |queue| queue.join(": ") }
59
+ process["weights"].sort_by { |queue| queue[0] }.map { |capsule| capsule.map { |name, weight| (weight > 0) ? "#{name}: #{weight}" : name }.join(", ") }
62
60
  else
63
61
  process["queues"].sort
64
62
  end
@@ -146,6 +146,9 @@ module Sidekiq
146
146
  end
147
147
  end
148
148
 
149
+ IGNORE_SHUTDOWN_INTERRUPTS = {Sidekiq::Shutdown => :never}
150
+ private_constant :IGNORE_SHUTDOWN_INTERRUPTS
151
+
149
152
  def process(uow)
150
153
  jobstr = uow.job
151
154
  queue = uow.queue_name
@@ -195,7 +198,7 @@ module Sidekiq
195
198
  ensure
196
199
  if ack
197
200
  # We don't want a shutdown signal to interrupt job acknowledgment.
198
- Thread.handle_interrupt(Sidekiq::Shutdown => :never) do
201
+ Thread.handle_interrupt(IGNORE_SHUTDOWN_INTERRUPTS) do
199
202
  uow.acknowledge
200
203
  end
201
204
  end
data/lib/sidekiq/rails.rb CHANGED
@@ -11,7 +11,8 @@ module Sidekiq
11
11
  end
12
12
 
13
13
  def call
14
- @app.reloader.wrap do
14
+ params = (::Rails::VERSION::STRING >= "7.1") ? {source: "job.sidekiq"} : {}
15
+ @app.reloader.wrap(**params) do
15
16
  yield
16
17
  end
17
18
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sidekiq
4
- VERSION = "7.0.2"
4
+ VERSION = "7.0.5"
5
5
  MAJOR = 7
6
6
  end
@@ -20,6 +20,12 @@ module Sidekiq
20
20
  "worker-src 'self'",
21
21
  "base-uri 'self'"
22
22
  ].join("; ").freeze
23
+ METRICS_PERIODS = {
24
+ "1h" => 60,
25
+ "2h" => 120,
26
+ "4h" => 240,
27
+ "8h" => 480
28
+ }
23
29
 
24
30
  def initialize(klass)
25
31
  @klass = klass
@@ -62,14 +68,20 @@ module Sidekiq
62
68
 
63
69
  get "/metrics" do
64
70
  q = Sidekiq::Metrics::Query.new
65
- @query_result = q.top_jobs
71
+ @period = params[:period]
72
+ @periods = METRICS_PERIODS
73
+ minutes = @periods.fetch(@period, @periods.values.first)
74
+ @query_result = q.top_jobs(minutes: minutes)
66
75
  erb(:metrics)
67
76
  end
68
77
 
69
78
  get "/metrics/:name" do
70
79
  @name = route_params[:name]
80
+ @period = params[:period]
71
81
  q = Sidekiq::Metrics::Query.new
72
- @query_result = q.for_job(@name)
82
+ @periods = METRICS_PERIODS
83
+ minutes = @periods.fetch(@period, @periods.values.first)
84
+ @query_result = q.for_job(@name, minutes: minutes)
73
85
  erb(:metrics_for_job)
74
86
  end
75
87
 
@@ -82,11 +94,14 @@ module Sidekiq
82
94
 
83
95
  post "/busy" do
84
96
  if params["identity"]
85
- p = Sidekiq::Process.new("identity" => params["identity"])
86
- p.quiet! if params["quiet"]
87
- p.stop! if params["stop"]
97
+ pro = Sidekiq::ProcessSet[params["identity"]]
98
+
99
+ pro.quiet! if params["quiet"]
100
+ pro.stop! if params["stop"]
88
101
  else
89
102
  processes.each do |pro|
103
+ next if pro.embedded?
104
+
90
105
  pro.quiet! if params["quiet"]
91
106
  pro.stop! if params["stop"]
92
107
  end
@@ -15,7 +15,7 @@ module Sidekiq
15
15
  # so extensions can be localized
16
16
  @strings[lang] ||= settings.locales.each_with_object({}) do |path, global|
17
17
  find_locale_files(lang).each do |file|
18
- strs = YAML.safe_load(File.open(file))
18
+ strs = YAML.safe_load(File.read(file))
19
19
  global.merge!(strs[lang])
20
20
  end
21
21
  end
@@ -118,7 +118,7 @@ module Sidekiq
118
118
  }.join(" ")
119
119
  end
120
120
 
121
- # mperham/sidekiq#3243
121
+ # sidekiq/sidekiq#3243
122
122
  def unfiltered?
123
123
  yield unless env["PATH_INFO"].start_with?("/filter/")
124
124
  end
@@ -161,6 +161,14 @@ module Sidekiq
161
161
  end
162
162
  end
163
163
 
164
+ def busy_weights(capsule_weights)
165
+ # backwards compat with 7.0.0, remove in 7.1
166
+ cw = [capsule_weights].flatten
167
+ cw.map { |hash|
168
+ hash.map { |name, weight| (weight > 0) ? +name << ": " << weight.to_s : name }.join(", ")
169
+ }.join("; ")
170
+ end
171
+
164
172
  def stats
165
173
  @stats ||= Sidekiq::Stats.new
166
174
  end
data/sidekiq.gemspec CHANGED
@@ -2,7 +2,7 @@ require_relative "lib/sidekiq/version"
2
2
 
3
3
  Gem::Specification.new do |gem|
4
4
  gem.authors = ["Mike Perham"]
5
- gem.email = ["mperham@gmail.com"]
5
+ gem.email = ["info@contribsys.com"]
6
6
  gem.summary = "Simple, efficient background processing for Ruby"
7
7
  gem.description = "Simple, efficient background processing for Ruby."
8
8
  gem.homepage = "https://sidekiq.org"
@@ -16,10 +16,10 @@ Gem::Specification.new do |gem|
16
16
 
17
17
  gem.metadata = {
18
18
  "homepage_uri" => "https://sidekiq.org",
19
- "bug_tracker_uri" => "https://github.com/mperham/sidekiq/issues",
20
- "documentation_uri" => "https://github.com/mperham/sidekiq/wiki",
21
- "changelog_uri" => "https://github.com/mperham/sidekiq/blob/main/Changes.md",
22
- "source_code_uri" => "https://github.com/mperham/sidekiq"
19
+ "bug_tracker_uri" => "https://github.com/sidekiq/sidekiq/issues",
20
+ "documentation_uri" => "https://github.com/sidekiq/sidekiq/wiki",
21
+ "changelog_uri" => "https://github.com/sidekiq/sidekiq/blob/main/Changes.md",
22
+ "source_code_uri" => "https://github.com/sidekiq/sidekiq"
23
23
  }
24
24
 
25
25
  gem.add_dependency "redis-client", ">= 0.11.0"
@@ -28,23 +28,11 @@ Gem::Specification.new do |gem|
28
28
  gem.add_dependency "concurrent-ruby", "< 2"
29
29
  gem.post_install_message = <<~EOM
30
30
 
31
- ####################################################
32
-
33
-
34
- █████████ █████ ██████████ ██████████ █████ ████ █████ ██████ ██████████ █████
35
- ███░░░░░███░░███ ░░███░░░░███ ░░███░░░░░█░░███ ███░ ░░███ ███░░░░███ ░███░░░░███ ███░░░███
36
- ░███ ░░░ ░███ ░███ ░░███ ░███ █ ░ ░███ ███ ░███ ███ ░░███ ░░░ ███ ███ ░░███
37
- ░░█████████ ░███ ░███ ░███ ░██████ ░███████ ░███ ░███ ░███ ███ ░███ ░███
38
- ░░░░░░░░███ ░███ ░███ ░███ ░███░░█ ░███░░███ ░███ ░███ ██░███ ███ ░███ ░███
39
- ███ ░███ ░███ ░███ ███ ░███ ░ █ ░███ ░░███ ░███ ░░███ ░░████ ███ ░░███ ███
40
- ░░█████████ █████ ██████████ ██████████ █████ ░░████ █████ ░░░██████░██ ███ ██ ░░░█████░
41
- ░░░░░░░░░ ░░░░░ ░░░░░░░░░░ ░░░░░░░░░░ ░░░░░ ░░░░ ░░░░░ ░░░░░░ ░░ ░░░ ░░ ░░░░░░
42
-
31
+ Welcome to Sidekiq 7.0!
43
32
 
44
33
  1. Use `gem 'sidekiq', '<7'` in your Gemfile if you don't want this new version.
45
- 2. Read the release notes at https://github.com/mperham/sidekiq/blob/main/docs/7.0-Upgrade.md
46
- 3. Search for open/closed issues at https://github.com/mperham/sidekiq/issues/
47
-
48
- ####################################################
34
+ 2. Read the release notes at https://github.com/sidekiq/sidekiq/blob/main/docs/7.0-Upgrade.md
35
+ 3. If you have problems, search for open/closed issues at https://github.com/sidekiq/sidekiq/issues/
36
+
49
37
  EOM
50
38
  end
@@ -4,6 +4,14 @@ class JobMetricsOverviewChart extends BaseChart {
4
4
  this.swatches = [];
5
5
  this.visibleKls = options.visibleKls;
6
6
 
7
+ const countBuckets = this.options.labels.length / 60;
8
+ this.labelBuckets = this.options.labels.reduce((acc, label, index) => {
9
+ const bucket = Math.floor(index / countBuckets);
10
+ acc[bucket] = acc[bucket] || [];
11
+ acc[bucket].push(label);
12
+ return acc;
13
+ }, []);
14
+
7
15
  this.init();
8
16
  }
9
17
 
@@ -52,7 +60,7 @@ class JobMetricsOverviewChart extends BaseChart {
52
60
 
53
61
  return {
54
62
  label: kls,
55
- data: this.options.series[kls],
63
+ data: this.buildSeries(kls),
56
64
  borderColor: color,
57
65
  backgroundColor: color,
58
66
  borderWidth: 2,
@@ -60,6 +68,26 @@ class JobMetricsOverviewChart extends BaseChart {
60
68
  };
61
69
  }
62
70
 
71
+ buildSeries(kls) {
72
+ // `series` is an object that maps labels to counts => { "20:15" => 2, "20:16" => 3, ... }
73
+ const series = this.options.series[kls];
74
+ return this.labelBuckets.reduce((acc, labels) => {
75
+ const bucketValues = labels.map(label => series[label]).filter(v => v);
76
+ if (bucketValues.length > 0) {
77
+ // Sum up the values for each bucket that has data.
78
+ // The new label is the bucket's first label, its start time.
79
+ acc[labels[0]] = bucketValues.reduce((a, b) => a + b, 0);
80
+ }
81
+ return acc;
82
+ }, {});
83
+ }
84
+
85
+ buildTooltipTitle(items) {
86
+ const [first, ...rest] = this.labelBuckets.find((labels) => labels[0] === items[0].label);
87
+ const title = [first, rest[rest.length - 1]].filter(v => v).join(" - ");
88
+ return `${title} UTC`
89
+ }
90
+
63
91
  get chartOptions() {
64
92
  return {
65
93
  ...super.chartOptions,
@@ -80,7 +108,7 @@ class JobMetricsOverviewChart extends BaseChart {
80
108
  tooltip: {
81
109
  ...super.chartOptions.plugins.tooltip,
82
110
  callbacks: {
83
- title: (items) => `${items[0].label} UTC`,
111
+ title: (items) => this.buildTooltipTitle(items),
84
112
  label: (item) =>
85
113
  `${item.dataset.label}: ${item.parsed.y.toFixed(1)} ` +
86
114
  `${this.options.units}`,
@@ -72,7 +72,7 @@ h1, h2, h3 {
72
72
  line-height: 45px;
73
73
  }
74
74
 
75
- .header-container {
75
+ .header-container, .header-container .page-title-container {
76
76
  display: flex;
77
77
  justify-content: space-between;
78
78
  align-items: center;
data/web/locales/da.yml CHANGED
@@ -1,11 +1,12 @@
1
1
  # elements like %{queue} are variables and should not be translated
2
2
  da:
3
- Actions: Actions
3
+ Actions: Handlinger
4
4
  AddToQueue: Tilføj til kø
5
5
  AreYouSure: Er du sikker?
6
6
  AreYouSureDeleteJob: Er du sikker på at du vil slette dette job?
7
7
  AreYouSureDeleteQueue: Er du sikker på at du vil slette %{queue} køen?
8
8
  Arguments: Argumenter
9
+ AvgExecutionTime: Gennemsnitlig eksekveringstid
9
10
  Busy: Travl
10
11
  Class: Klasse
11
12
  Connections: Forbindelser
@@ -18,21 +19,25 @@ da:
18
19
  Enqueued: I kø
19
20
  Error: Fejl
20
21
  ErrorBacktrace: Fejl backtrace
21
- ErrorClass: Fejl klasse
22
- ErrorMessage: Fejl besked
22
+ ErrorClass: Fejlklasse
23
+ ErrorMessage: Fejlbesked
23
24
  Extras: Ekstra
24
25
  Failed: Fejlet
26
+ Failure: Fejl
25
27
  Failures: Fejl
26
28
  GoBack: ← Tilbage
27
29
  History: Historik
28
30
  Job: Job
29
31
  Jobs: Jobs
32
+ Latency: Forsinkelse
30
33
  LastRetry: Sidste forsøg
31
34
  LivePoll: Live Poll
32
35
  MemoryUsage: RAM forbrug
36
+ Name: Navn
33
37
  Namespace: Namespace
34
38
  NextRetry: Næste forsøg
35
39
  NoDeadJobsFound: Ingen døde jobs fundet
40
+ NoJobMetricsFound: Ingen nylig job-metrics blev fundet
36
41
  NoRetriesFound: Ingen gen-forsøg var fundet
37
42
  NoScheduledFound: Ingen jobs i kø fundet
38
43
  OneMonth: 1 måned
@@ -43,7 +48,7 @@ da:
43
48
  Processes: Processer
44
49
  Queue: Kø
45
50
  Queues: Køer
46
- Realtime: Real-time
51
+ Realtime: Realtid
47
52
  Retries: Forsøg
48
53
  RetryAll: Forsøg alle
49
54
  RetryCount: Antal forsøg
@@ -56,10 +61,12 @@ da:
56
61
  Started: Startet
57
62
  Status: Status
58
63
  StopPolling: Stop Polling
64
+ Success: Succes
59
65
  Thread: Tråd
60
66
  Threads: Tråde
61
67
  ThreeMonths: 3 måneder
62
68
  Time: Tid
69
+ TotalExecutionTime: Total eksekveringstid
63
70
  Uptime: Oppetid (dage)
64
71
  Version: Version
65
72
  When: Når
@@ -12,10 +12,10 @@
12
12
  <p id="serverUtcTime" class="navbar-text server-utc-time"><%= server_utc_time %></p>
13
13
  </li>
14
14
  <li>
15
- <p class="navbar-text"><a rel=help href="https://github.com/mperham/sidekiq/wiki">docs</a></p>
15
+ <p class="navbar-text"><a rel=help href="https://github.com/sidekiq/sidekiq/wiki">docs</a></p>
16
16
  </li>
17
17
  <li>
18
- <p class="navbar-text"><a rel=external href="https://github.com/mperham/sidekiq/tree/main/web/locales"><%= locale %></a></p>
18
+ <p class="navbar-text"><a rel=external href="https://github.com/sidekiq/sidekiq/tree/main/web/locales"><%= locale %></a></p>
19
19
  </li>
20
20
  </ul>
21
21
  </div>