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.
- checksums.yaml +4 -4
- data/Changes.md +30 -9
- data/README.md +29 -22
- data/bin/sidekiqload +186 -109
- data/bin/sidekiqmon +3 -0
- data/lib/sidekiq/api.rb +31 -4
- data/lib/sidekiq/capsule.rb +17 -0
- data/lib/sidekiq/cli.rb +3 -2
- data/lib/sidekiq/component.rb +2 -0
- data/lib/sidekiq/config.rb +1 -1
- data/lib/sidekiq/embedded.rb +1 -1
- data/lib/sidekiq/fetch.rb +2 -4
- data/lib/sidekiq/job_retry.rb +1 -1
- data/lib/sidekiq/job_util.rb +61 -13
- data/lib/sidekiq/launcher.rb +10 -7
- data/lib/sidekiq/metrics/tracking.rb +2 -0
- data/lib/sidekiq/middleware/chain.rb +12 -9
- data/lib/sidekiq/middleware/current_attributes.rb +5 -7
- data/lib/sidekiq/monitor.rb +1 -3
- data/lib/sidekiq/processor.rb +4 -1
- data/lib/sidekiq/rails.rb +2 -1
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/application.rb +20 -5
- data/lib/sidekiq/web/helpers.rb +10 -2
- data/sidekiq.gemspec +9 -21
- data/web/assets/javascripts/metrics.js +30 -2
- data/web/assets/stylesheets/application.css +1 -1
- data/web/locales/da.yml +11 -4
- data/web/views/_footer.erb +2 -2
- data/web/views/_job_info.erb +2 -2
- data/web/views/_metrics_period_select.erb +12 -0
- data/web/views/_paging.erb +2 -0
- data/web/views/busy.erb +24 -26
- data/web/views/metrics.erb +6 -4
- data/web/views/metrics_for_job.erb +9 -7
- data/web/views/morgue.erb +4 -8
- data/web/views/queue.erb +10 -14
- data/web/views/queues.erb +3 -1
- data/web/views/retries.erb +4 -8
- data/web/views/scheduled.erb +12 -13
- metadata +14 -24
data/lib/sidekiq/capsule.rb
CHANGED
@@ -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/
|
87
|
+
See: https://github.com/sidekiq/sidekiq/wiki/Using-Redis#memory
|
87
88
|
|
88
89
|
EOM
|
89
90
|
end
|
data/lib/sidekiq/component.rb
CHANGED
data/lib/sidekiq/config.rb
CHANGED
@@ -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(
|
132
|
+
RedisConnection.create({size: size, logger: logger, pool_name: name}.merge(@redis_config))
|
133
133
|
end
|
134
134
|
|
135
135
|
def redis_info
|
data/lib/sidekiq/embedded.rb
CHANGED
@@ -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/
|
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 =
|
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
|
data/lib/sidekiq/job_retry.rb
CHANGED
@@ -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.
|
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:
|
data/lib/sidekiq/job_util.rb
CHANGED
@@ -17,18 +17,24 @@ module Sidekiq
|
|
17
17
|
|
18
18
|
def verify_json(item)
|
19
19
|
job_class = item["wrapped"] || item["class"]
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
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
|
data/lib/sidekiq/launcher.rb
CHANGED
@@ -161,7 +161,7 @@ module Sidekiq
|
|
161
161
|
fails = procd = 0
|
162
162
|
kb = memory_usage(::Process.pid)
|
163
163
|
|
164
|
-
_, exists, _, _,
|
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
|
-
|
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/
|
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" =>
|
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.
|
@@ -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
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
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
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
data/lib/sidekiq/monitor.rb
CHANGED
@@ -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 { |
|
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
|
data/lib/sidekiq/processor.rb
CHANGED
@@ -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(
|
201
|
+
Thread.handle_interrupt(IGNORE_SHUTDOWN_INTERRUPTS) do
|
199
202
|
uow.acknowledge
|
200
203
|
end
|
201
204
|
end
|
data/lib/sidekiq/rails.rb
CHANGED
data/lib/sidekiq/version.rb
CHANGED
@@ -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
|
-
@
|
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
|
-
@
|
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
|
-
|
86
|
-
|
87
|
-
|
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
|
data/lib/sidekiq/web/helpers.rb
CHANGED
@@ -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.
|
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
|
-
#
|
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 = ["
|
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/
|
20
|
-
"documentation_uri" => "https://github.com/
|
21
|
-
"changelog_uri" => "https://github.com/
|
22
|
-
"source_code_uri" => "https://github.com/
|
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/
|
46
|
-
3.
|
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.
|
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) =>
|
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}`,
|
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:
|
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:
|
22
|
-
ErrorMessage:
|
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:
|
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
|
data/web/views/_footer.erb
CHANGED
@@ -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/
|
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/
|
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>
|