sidekiq 5.2.7 → 8.0.5
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 +4 -4
- data/Changes.md +845 -8
- data/LICENSE.txt +9 -0
- data/README.md +54 -54
- data/bin/multi_queue_bench +271 -0
- data/bin/sidekiq +22 -3
- data/bin/sidekiqload +219 -112
- data/bin/sidekiqmon +11 -0
- data/bin/webload +69 -0
- data/lib/active_job/queue_adapters/sidekiq_adapter.rb +120 -0
- data/lib/generators/sidekiq/job_generator.rb +59 -0
- data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
- data/lib/generators/sidekiq/templates/{worker_spec.rb.erb → job_spec.rb.erb} +1 -1
- data/lib/generators/sidekiq/templates/{worker_test.rb.erb → job_test.rb.erb} +1 -1
- data/lib/sidekiq/api.rb +757 -373
- data/lib/sidekiq/capsule.rb +132 -0
- data/lib/sidekiq/cli.rb +210 -233
- data/lib/sidekiq/client.rb +145 -103
- data/lib/sidekiq/component.rb +128 -0
- data/lib/sidekiq/config.rb +315 -0
- data/lib/sidekiq/deploy.rb +64 -0
- data/lib/sidekiq/embedded.rb +64 -0
- data/lib/sidekiq/fetch.rb +49 -42
- data/lib/sidekiq/iterable_job.rb +56 -0
- data/lib/sidekiq/job/interrupt_handler.rb +24 -0
- data/lib/sidekiq/job/iterable/active_record_enumerator.rb +53 -0
- data/lib/sidekiq/job/iterable/csv_enumerator.rb +47 -0
- data/lib/sidekiq/job/iterable/enumerators.rb +135 -0
- data/lib/sidekiq/job/iterable.rb +306 -0
- data/lib/sidekiq/job.rb +385 -0
- data/lib/sidekiq/job_logger.rb +34 -7
- data/lib/sidekiq/job_retry.rb +164 -109
- data/lib/sidekiq/job_util.rb +113 -0
- data/lib/sidekiq/launcher.rb +208 -107
- data/lib/sidekiq/logger.rb +80 -0
- data/lib/sidekiq/manager.rb +42 -46
- data/lib/sidekiq/metrics/query.rb +184 -0
- data/lib/sidekiq/metrics/shared.rb +109 -0
- data/lib/sidekiq/metrics/tracking.rb +150 -0
- data/lib/sidekiq/middleware/chain.rb +113 -56
- data/lib/sidekiq/middleware/current_attributes.rb +119 -0
- data/lib/sidekiq/middleware/i18n.rb +7 -7
- data/lib/sidekiq/middleware/modules.rb +23 -0
- data/lib/sidekiq/monitor.rb +147 -0
- data/lib/sidekiq/paginator.rb +41 -16
- data/lib/sidekiq/processor.rb +146 -127
- data/lib/sidekiq/profiler.rb +72 -0
- data/lib/sidekiq/rails.rb +46 -43
- data/lib/sidekiq/redis_client_adapter.rb +113 -0
- data/lib/sidekiq/redis_connection.rb +79 -108
- data/lib/sidekiq/ring_buffer.rb +31 -0
- data/lib/sidekiq/scheduled.rb +112 -50
- data/lib/sidekiq/sd_notify.rb +149 -0
- data/lib/sidekiq/systemd.rb +26 -0
- data/lib/sidekiq/testing/inline.rb +6 -5
- data/lib/sidekiq/testing.rb +91 -90
- data/lib/sidekiq/transaction_aware_client.rb +51 -0
- data/lib/sidekiq/version.rb +7 -1
- data/lib/sidekiq/web/action.rb +125 -60
- data/lib/sidekiq/web/application.rb +363 -259
- data/lib/sidekiq/web/config.rb +120 -0
- data/lib/sidekiq/web/csrf_protection.rb +183 -0
- data/lib/sidekiq/web/helpers.rb +241 -120
- data/lib/sidekiq/web/router.rb +62 -71
- data/lib/sidekiq/web.rb +69 -161
- data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
- data/lib/sidekiq.rb +94 -182
- data/sidekiq.gemspec +26 -16
- data/web/assets/images/apple-touch-icon.png +0 -0
- data/web/assets/javascripts/application.js +150 -61
- data/web/assets/javascripts/base-charts.js +120 -0
- data/web/assets/javascripts/chart.min.js +13 -0
- data/web/assets/javascripts/chartjs-adapter-date-fns.min.js +7 -0
- data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
- data/web/assets/javascripts/dashboard-charts.js +194 -0
- data/web/assets/javascripts/dashboard.js +41 -293
- data/web/assets/javascripts/metrics.js +280 -0
- data/web/assets/stylesheets/style.css +766 -0
- data/web/locales/ar.yml +72 -65
- data/web/locales/cs.yml +63 -62
- data/web/locales/da.yml +61 -53
- data/web/locales/de.yml +66 -53
- data/web/locales/el.yml +44 -24
- data/web/locales/en.yml +94 -66
- data/web/locales/es.yml +92 -54
- data/web/locales/fa.yml +66 -65
- data/web/locales/fr.yml +83 -62
- data/web/locales/gd.yml +99 -0
- data/web/locales/he.yml +66 -64
- data/web/locales/hi.yml +60 -59
- data/web/locales/it.yml +93 -54
- data/web/locales/ja.yml +75 -64
- data/web/locales/ko.yml +53 -52
- data/web/locales/lt.yml +84 -0
- data/web/locales/nb.yml +62 -61
- data/web/locales/nl.yml +53 -52
- data/web/locales/pl.yml +46 -45
- data/web/locales/{pt-br.yml → pt-BR.yml} +84 -56
- data/web/locales/pt.yml +52 -51
- data/web/locales/ru.yml +69 -63
- data/web/locales/sv.yml +54 -53
- data/web/locales/ta.yml +61 -60
- data/web/locales/tr.yml +101 -0
- data/web/locales/uk.yml +86 -61
- data/web/locales/ur.yml +65 -64
- data/web/locales/vi.yml +84 -0
- data/web/locales/zh-CN.yml +106 -0
- data/web/locales/{zh-tw.yml → zh-TW.yml} +43 -9
- data/web/views/_footer.erb +31 -19
- data/web/views/_job_info.erb +94 -75
- data/web/views/_metrics_period_select.erb +15 -0
- data/web/views/_nav.erb +14 -21
- data/web/views/_paging.erb +23 -19
- data/web/views/_poll_link.erb +3 -6
- data/web/views/_summary.erb +23 -23
- data/web/views/busy.erb +139 -87
- data/web/views/dashboard.erb +82 -53
- data/web/views/dead.erb +31 -27
- data/web/views/filtering.erb +6 -0
- data/web/views/layout.erb +15 -29
- data/web/views/metrics.erb +84 -0
- data/web/views/metrics_for_job.erb +58 -0
- data/web/views/morgue.erb +60 -70
- data/web/views/profiles.erb +43 -0
- data/web/views/queue.erb +50 -39
- data/web/views/queues.erb +45 -29
- data/web/views/retries.erb +65 -75
- data/web/views/retry.erb +32 -27
- data/web/views/scheduled.erb +58 -52
- data/web/views/scheduled_job_info.erb +1 -1
- metadata +96 -76
- data/.circleci/config.yml +0 -61
- data/.github/contributing.md +0 -32
- data/.github/issue_template.md +0 -11
- data/.gitignore +0 -15
- data/.travis.yml +0 -11
- data/3.0-Upgrade.md +0 -70
- data/4.0-Upgrade.md +0 -53
- data/5.0-Upgrade.md +0 -56
- data/COMM-LICENSE +0 -97
- data/Ent-Changes.md +0 -238
- data/Gemfile +0 -23
- data/LICENSE +0 -9
- data/Pro-2.0-Upgrade.md +0 -138
- data/Pro-3.0-Upgrade.md +0 -44
- data/Pro-4.0-Upgrade.md +0 -35
- data/Pro-Changes.md +0 -759
- data/Rakefile +0 -9
- data/bin/sidekiqctl +0 -20
- data/code_of_conduct.md +0 -50
- data/lib/generators/sidekiq/worker_generator.rb +0 -49
- data/lib/sidekiq/core_ext.rb +0 -1
- data/lib/sidekiq/ctl.rb +0 -221
- data/lib/sidekiq/delay.rb +0 -42
- data/lib/sidekiq/exception_handler.rb +0 -29
- data/lib/sidekiq/extensions/action_mailer.rb +0 -57
- data/lib/sidekiq/extensions/active_record.rb +0 -40
- data/lib/sidekiq/extensions/class_methods.rb +0 -40
- data/lib/sidekiq/extensions/generic_proxy.rb +0 -31
- data/lib/sidekiq/logging.rb +0 -122
- data/lib/sidekiq/middleware/server/active_record.rb +0 -23
- data/lib/sidekiq/util.rb +0 -66
- data/lib/sidekiq/worker.rb +0 -220
- data/web/assets/stylesheets/application-rtl.css +0 -246
- data/web/assets/stylesheets/application.css +0 -1144
- data/web/assets/stylesheets/bootstrap-rtl.min.css +0 -9
- data/web/assets/stylesheets/bootstrap.css +0 -5
- data/web/locales/zh-cn.yml +0 -68
- data/web/views/_status.erb +0 -4
data/lib/sidekiq/web/helpers.rb
CHANGED
@@ -1,26 +1,96 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
2
|
+
|
3
|
+
require "uri"
|
4
|
+
require "yaml"
|
5
|
+
require "cgi/escape"
|
6
6
|
|
7
7
|
module Sidekiq
|
8
|
-
#
|
8
|
+
# These methods are available to pages within the Web UI and UI extensions.
|
9
|
+
# They are not public APIs for applications to use.
|
9
10
|
module WebHelpers
|
11
|
+
def store_name
|
12
|
+
hash = redis_info
|
13
|
+
return "Dragonfly" if hash.has_key?("dragonfly_version")
|
14
|
+
return "Valkey" if hash.has_key?("valkey_version")
|
15
|
+
"Redis"
|
16
|
+
end
|
17
|
+
|
18
|
+
def store_version
|
19
|
+
hash = redis_info
|
20
|
+
return hash["dragonfly_version"] if hash.has_key?("dragonfly_version")
|
21
|
+
return hash["valkey_version"] if hash.has_key?("valkey_version")
|
22
|
+
hash["redis_version"]
|
23
|
+
end
|
24
|
+
|
25
|
+
def style_tag(location, **kwargs)
|
26
|
+
global = location.match?(/:\/\//)
|
27
|
+
location = root_path + location if !global && !location.start_with?(root_path)
|
28
|
+
attrs = {
|
29
|
+
type: "text/css",
|
30
|
+
media: "screen",
|
31
|
+
rel: "stylesheet",
|
32
|
+
nonce: csp_nonce,
|
33
|
+
href: location
|
34
|
+
}
|
35
|
+
add_to_head do
|
36
|
+
html_tag(:link, attrs.merge(kwargs))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def script_tag(location, **kwargs)
|
41
|
+
global = location.match?(/:\/\//)
|
42
|
+
location = root_path + location if !global && !location.start_with?(root_path)
|
43
|
+
attrs = {
|
44
|
+
type: "text/javascript",
|
45
|
+
nonce: csp_nonce,
|
46
|
+
src: location
|
47
|
+
}
|
48
|
+
html_tag(:script, attrs.merge(kwargs)) {}
|
49
|
+
end
|
50
|
+
|
51
|
+
# NB: keys and values are not escaped; do not allow user input
|
52
|
+
# in the attributes
|
53
|
+
private def html_tag(tagname, attrs)
|
54
|
+
s = "<#{tagname}"
|
55
|
+
attrs.each_pair do |k, v|
|
56
|
+
next unless v
|
57
|
+
s << " #{k}=\"#{v}\""
|
58
|
+
end
|
59
|
+
if block_given?
|
60
|
+
s << ">"
|
61
|
+
yield s
|
62
|
+
s << "</#{tagname}>"
|
63
|
+
else
|
64
|
+
s << " />"
|
65
|
+
end
|
66
|
+
s
|
67
|
+
end
|
68
|
+
|
10
69
|
def strings(lang)
|
11
70
|
@@strings ||= {}
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
71
|
+
|
72
|
+
# Allow sidekiq-web extensions to add locale paths
|
73
|
+
# so extensions can be localized
|
74
|
+
@@strings[lang] ||= config.locales.each_with_object({}) do |path, global|
|
75
|
+
find_locale_files(lang).each do |file|
|
76
|
+
strs = YAML.safe_load_file(file)
|
77
|
+
global.merge!(strs[lang])
|
20
78
|
end
|
21
79
|
end
|
22
80
|
end
|
23
81
|
|
82
|
+
def to_json(x)
|
83
|
+
Sidekiq.dump_json(x)
|
84
|
+
end
|
85
|
+
|
86
|
+
def singularize(str, count)
|
87
|
+
if count == 1 && str.respond_to?(:singularize) # rails
|
88
|
+
str.singularize
|
89
|
+
else
|
90
|
+
str
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
24
94
|
def clear_caches
|
25
95
|
@@strings = nil
|
26
96
|
@@locale_files = nil
|
@@ -28,21 +98,46 @@ module Sidekiq
|
|
28
98
|
end
|
29
99
|
|
30
100
|
def locale_files
|
31
|
-
@@locale_files ||=
|
101
|
+
@@locale_files ||= config.locales.flat_map { |path|
|
32
102
|
Dir["#{path}/*.yml"]
|
33
|
-
|
103
|
+
}
|
34
104
|
end
|
35
105
|
|
36
106
|
def available_locales
|
37
|
-
@@available_locales ||= locale_files.map { |path| File.basename(path,
|
107
|
+
@@available_locales ||= Set.new(locale_files.map { |path| File.basename(path, ".yml") })
|
38
108
|
end
|
39
109
|
|
40
110
|
def find_locale_files(lang)
|
41
111
|
locale_files.select { |file| file =~ /\/#{lang}\.yml$/ }
|
42
112
|
end
|
43
113
|
|
44
|
-
|
45
|
-
|
114
|
+
def language_name(locale)
|
115
|
+
strings(locale).fetch("LanguageName", locale)
|
116
|
+
end
|
117
|
+
|
118
|
+
def search(jobset, substr)
|
119
|
+
resultset = jobset.scan(substr).to_a
|
120
|
+
@current_page = 1
|
121
|
+
@count = @total_size = resultset.size
|
122
|
+
resultset
|
123
|
+
end
|
124
|
+
|
125
|
+
def filtering(which)
|
126
|
+
erb(:filtering, locals: {which: which})
|
127
|
+
end
|
128
|
+
|
129
|
+
def filter_link(jid, within = "retries")
|
130
|
+
if within.nil?
|
131
|
+
::Rack::Utils.escape_html(jid)
|
132
|
+
else
|
133
|
+
"<a href='#{root_path}#{within}?substr=#{jid}'>#{::Rack::Utils.escape_html(jid)}</a>"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def display_tags(job, within = "retries")
|
138
|
+
job.tags.map { |tag|
|
139
|
+
"<span class='label label-info jobtag jobtag-#{Rack::Utils.escape_html(tag)}'>#{filter_link(tag, within)}</span>"
|
140
|
+
}.join(" ")
|
46
141
|
end
|
47
142
|
|
48
143
|
# This view helper provide ability display you html code in
|
@@ -62,66 +157,73 @@ module Sidekiq
|
|
62
157
|
@head_html.join if defined?(@head_html)
|
63
158
|
end
|
64
159
|
|
65
|
-
def poll_path
|
66
|
-
if current_path != '' && params['poll']
|
67
|
-
root_path + current_path
|
68
|
-
else
|
69
|
-
""
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
160
|
def text_direction
|
74
|
-
get_locale[
|
161
|
+
get_locale["TextDirection"] || "ltr"
|
75
162
|
end
|
76
163
|
|
77
164
|
def rtl?
|
78
|
-
text_direction ==
|
165
|
+
text_direction == "rtl"
|
79
166
|
end
|
80
167
|
|
81
|
-
# See https://www.
|
168
|
+
# See https://www.rfc-editor.org/rfc/rfc9110.html#section-12.5.4
|
169
|
+
# Returns an array of language tags ordered by their quality value
|
170
|
+
#
|
171
|
+
# Inspiration taken from https://github.com/iain/http_accept_language/blob/master/lib/http_accept_language/parser.rb
|
82
172
|
def user_preferred_languages
|
83
|
-
languages = env[
|
84
|
-
languages.to_s.
|
85
|
-
locale, quality = language.split(
|
86
|
-
locale
|
173
|
+
languages = env["HTTP_ACCEPT_LANGUAGE"]
|
174
|
+
languages.to_s.gsub(/\s+/, "").split(",").map { |language|
|
175
|
+
locale, quality = language.split(";q=", 2)
|
176
|
+
locale = nil if locale == "*" # Ignore wildcards
|
87
177
|
quality = quality ? quality.to_f : 1.0
|
88
178
|
[locale, quality]
|
89
|
-
|
179
|
+
}.sort { |(_, left), (_, right)|
|
90
180
|
right <=> left
|
91
|
-
|
181
|
+
}.map(&:first).compact
|
92
182
|
end
|
93
183
|
|
94
184
|
# Given an Accept-Language header like "fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4,ru;q=0.2"
|
95
185
|
# this method will try to best match the available locales to the user's preferred languages.
|
96
|
-
#
|
97
|
-
# Inspiration taken from https://github.com/iain/http_accept_language/blob/master/lib/http_accept_language/parser.rb
|
98
186
|
def locale
|
99
|
-
|
100
|
-
|
101
|
-
|
187
|
+
# session[:locale] is set via the locale selector from the footer
|
188
|
+
@locale ||= if (l = session&.fetch(:locale, nil)) && available_locales.include?(l)
|
189
|
+
l
|
190
|
+
else
|
191
|
+
matched_locale = nil
|
192
|
+
# Attempt to find a case-insensitive exact match first
|
193
|
+
user_preferred_languages.each do |preferred|
|
194
|
+
# We only care about the language and primary subtag
|
195
|
+
# "en-GB-oxendict" becomes "en-GB"
|
196
|
+
language_tag = preferred.split("-")[0..1].join("-")
|
197
|
+
matched_locale = available_locales.find { |available_locale| available_locale.casecmp?(language_tag) }
|
198
|
+
break if matched_locale
|
199
|
+
end
|
102
200
|
|
103
|
-
|
104
|
-
preferred_language == available.split('-', 2).first
|
105
|
-
end
|
201
|
+
return matched_locale if matched_locale
|
106
202
|
|
107
|
-
|
108
|
-
|
203
|
+
# Find the first base language match
|
204
|
+
# "en-US,es-MX;q=0.9" matches "en"
|
205
|
+
user_preferred_languages.each do |preferred|
|
206
|
+
base_language = preferred.split("-", 2).first
|
207
|
+
matched_locale = available_locales.find { |available_locale| available_locale.casecmp?(base_language) }
|
208
|
+
break if matched_locale
|
209
|
+
end
|
109
210
|
|
110
|
-
matched_locale ||
|
211
|
+
matched_locale || "en"
|
111
212
|
end
|
112
213
|
end
|
113
214
|
|
114
|
-
#
|
215
|
+
# sidekiq/sidekiq#3243
|
115
216
|
def unfiltered?
|
116
|
-
|
217
|
+
s = url_params("substr")
|
218
|
+
yield unless s && s.size > 0
|
117
219
|
end
|
118
220
|
|
119
221
|
def get_locale
|
120
222
|
strings(locale)
|
121
223
|
end
|
122
224
|
|
123
|
-
def t(msg, options={})
|
124
|
-
string = get_locale[msg] || strings(
|
225
|
+
def t(msg, options = {})
|
226
|
+
string = get_locale[msg] || strings("en")[msg] || msg
|
125
227
|
if options.empty?
|
126
228
|
string
|
127
229
|
else
|
@@ -129,118 +231,135 @@ module Sidekiq
|
|
129
231
|
end
|
130
232
|
end
|
131
233
|
|
132
|
-
def
|
133
|
-
|
234
|
+
def sort_direction_label
|
235
|
+
(url_params("direction") == "asc") ? "↑" : "↓"
|
236
|
+
end
|
237
|
+
|
238
|
+
def workset
|
239
|
+
@work ||= Sidekiq::WorkSet.new
|
134
240
|
end
|
135
241
|
|
136
242
|
def processes
|
137
243
|
@processes ||= Sidekiq::ProcessSet.new
|
138
244
|
end
|
139
245
|
|
140
|
-
|
141
|
-
|
246
|
+
# Sorts processes by hostname following the natural sort order
|
247
|
+
def sorted_processes
|
248
|
+
@sorted_processes ||= begin
|
249
|
+
return processes unless processes.all? { |p| p["hostname"] }
|
250
|
+
|
251
|
+
processes.to_a.sort_by do |process|
|
252
|
+
# Kudos to `shurikk` on StackOverflow
|
253
|
+
# https://stackoverflow.com/a/15170063/575547
|
254
|
+
process["hostname"].split(/(\d+)/).map { |a| /\d+/.match?(a) ? a.to_i : a }
|
255
|
+
end
|
256
|
+
end
|
142
257
|
end
|
143
258
|
|
144
|
-
def
|
145
|
-
|
146
|
-
|
147
|
-
|
259
|
+
def busy_weights(capsule_weights)
|
260
|
+
# backwards compat with 7.0.0, remove in 7.1
|
261
|
+
cw = [capsule_weights].flatten
|
262
|
+
cw.map { |hash|
|
263
|
+
hash.map { |name, weight| (weight > 0) ? +name << ": " << weight.to_s : name }.join(", ")
|
264
|
+
}.join("; ")
|
148
265
|
end
|
149
266
|
|
150
|
-
def
|
151
|
-
Sidekiq.
|
152
|
-
c = conn.connection
|
153
|
-
"redis://#{c[:location]}/#{c[:db]}"
|
154
|
-
end
|
267
|
+
def stats
|
268
|
+
@stats ||= Sidekiq::Stats.new
|
155
269
|
end
|
156
270
|
|
157
|
-
def
|
158
|
-
|
271
|
+
def redis_url
|
272
|
+
Sidekiq.redis do |conn|
|
273
|
+
conn.config.server_url
|
274
|
+
end
|
159
275
|
end
|
160
276
|
|
161
277
|
def redis_info
|
162
|
-
Sidekiq.redis_info
|
278
|
+
@info ||= Sidekiq.default_configuration.redis_info
|
163
279
|
end
|
164
280
|
|
165
281
|
def root_path
|
166
|
-
"#{env[
|
282
|
+
"#{env["SCRIPT_NAME"]}/"
|
167
283
|
end
|
168
284
|
|
169
285
|
def current_path
|
170
|
-
@current_path ||= request.path_info.gsub(/^\//,
|
286
|
+
@current_path ||= request.path_info.gsub(/^\//, "")
|
171
287
|
end
|
172
288
|
|
173
289
|
def current_status
|
174
|
-
|
290
|
+
(workset.size == 0) ? "idle" : "active"
|
175
291
|
end
|
176
292
|
|
177
293
|
def relative_time(time)
|
178
294
|
stamp = time.getutc.iso8601
|
179
|
-
%
|
295
|
+
%(<time class="ltr" dir="ltr" title="#{stamp}" datetime="#{stamp}">#{time}</time>)
|
180
296
|
end
|
181
297
|
|
182
298
|
def job_params(job, score)
|
183
|
-
"#{score}-#{job[
|
299
|
+
"#{score}-#{job["jid"]}"
|
184
300
|
end
|
185
301
|
|
186
|
-
def
|
187
|
-
score, jid =
|
302
|
+
def parse_key(key)
|
303
|
+
score, jid = key.split("-", 2)
|
188
304
|
[score.to_f, jid]
|
189
305
|
end
|
190
306
|
|
191
|
-
SAFE_QPARAMS = %w
|
307
|
+
SAFE_QPARAMS = %w[page direction]
|
192
308
|
|
193
309
|
# Merge options with current params, filter safe params, and stringify to query string
|
194
310
|
def qparams(options)
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
311
|
+
stringified_options = options.transform_keys(&:to_s)
|
312
|
+
|
313
|
+
to_query_string(request.params.merge(stringified_options))
|
314
|
+
end
|
199
315
|
|
200
|
-
|
316
|
+
def to_query_string(hash)
|
317
|
+
hash.map { |key, value|
|
201
318
|
SAFE_QPARAMS.include?(key) ? "#{key}=#{CGI.escape(value.to_s)}" : next
|
202
|
-
|
319
|
+
}.compact.join("&")
|
203
320
|
end
|
204
321
|
|
205
322
|
def truncate(text, truncate_after_chars = 2000)
|
206
|
-
truncate_after_chars && text.size > truncate_after_chars ? "#{text[0..truncate_after_chars]}..." : text
|
323
|
+
(truncate_after_chars && text.size > truncate_after_chars) ? "#{text[0..truncate_after_chars]}..." : text
|
207
324
|
end
|
208
325
|
|
209
326
|
def display_args(args, truncate_after_chars = 2000)
|
210
|
-
return "Invalid job payload, args is nil" if args
|
211
|
-
return "Invalid job payload, args must be an Array, not #{args.class.name}"
|
327
|
+
return "Invalid job payload, args is nil" if args.nil?
|
328
|
+
return "Invalid job payload, args must be an Array, not #{args.class.name}" unless args.is_a?(Array)
|
212
329
|
|
213
330
|
begin
|
214
|
-
args.map
|
331
|
+
args.map { |arg|
|
215
332
|
h(truncate(to_display(arg), truncate_after_chars))
|
216
|
-
|
333
|
+
}.join(", ")
|
217
334
|
rescue
|
218
335
|
"Illegal job arguments: #{h args.inspect}"
|
219
336
|
end
|
220
337
|
end
|
221
338
|
|
222
339
|
def csrf_tag
|
223
|
-
"<input type='hidden' name='authenticity_token' value='#{
|
340
|
+
"<input type='hidden' name='authenticity_token' value='#{env[:csrf_token]}'/>"
|
341
|
+
end
|
342
|
+
|
343
|
+
def csp_nonce
|
344
|
+
env[:csp_nonce]
|
224
345
|
end
|
225
346
|
|
226
347
|
def to_display(arg)
|
348
|
+
arg.inspect
|
349
|
+
rescue
|
227
350
|
begin
|
228
|
-
arg.
|
229
|
-
rescue
|
230
|
-
|
231
|
-
arg.to_s
|
232
|
-
rescue => ex
|
233
|
-
"Cannot display argument: [#{ex.class.name}] #{ex.message}"
|
234
|
-
end
|
351
|
+
arg.to_s
|
352
|
+
rescue => ex
|
353
|
+
"Cannot display argument: [#{ex.class.name}] #{ex.message}"
|
235
354
|
end
|
236
355
|
end
|
237
356
|
|
238
|
-
RETRY_JOB_KEYS = Set.new(%w
|
357
|
+
RETRY_JOB_KEYS = Set.new(%w[
|
239
358
|
queue class args retry_count retried_at failed_at
|
240
359
|
jid error_message error_class backtrace
|
241
360
|
error_backtrace enqueued_at retry wrapped
|
242
|
-
created_at
|
243
|
-
)
|
361
|
+
created_at tags display_class
|
362
|
+
])
|
244
363
|
|
245
364
|
def retry_extra_items(retry_job)
|
246
365
|
@retry_extra_items ||= {}.tap do |extra|
|
@@ -250,24 +369,28 @@ module Sidekiq
|
|
250
369
|
end
|
251
370
|
end
|
252
371
|
|
253
|
-
def
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
372
|
+
def format_memory(rss_kb)
|
373
|
+
return "0" if rss_kb.nil? || rss_kb == 0
|
374
|
+
|
375
|
+
if rss_kb < 100_000
|
376
|
+
"#{number_with_delimiter(rss_kb)} KB"
|
377
|
+
elsif rss_kb < 10_000_000
|
378
|
+
"#{number_with_delimiter((rss_kb / 1024.0).to_i)} MB"
|
379
|
+
else
|
380
|
+
"#{number_with_delimiter(rss_kb / (1024.0 * 1024.0), precision: 1)} GB"
|
258
381
|
end
|
382
|
+
end
|
259
383
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
parts.join(options[:separator])
|
384
|
+
def number_with_delimiter(number, options = {})
|
385
|
+
precision = options[:precision] || 0
|
386
|
+
%(<span data-nwp="#{precision}">#{number.round(precision)}</span>)
|
264
387
|
end
|
265
388
|
|
266
389
|
def h(text)
|
267
|
-
::Rack::Utils.escape_html(text)
|
390
|
+
::Rack::Utils.escape_html(text.to_s)
|
268
391
|
rescue ArgumentError => e
|
269
|
-
raise unless e.message.eql?(
|
270
|
-
text.encode!(
|
392
|
+
raise unless e.message.eql?("invalid byte sequence in UTF-8")
|
393
|
+
text.encode!("UTF-16", "UTF-8", invalid: :replace, replace: "").encode!("UTF-8", "UTF-16")
|
271
394
|
retry
|
272
395
|
end
|
273
396
|
|
@@ -284,7 +407,7 @@ module Sidekiq
|
|
284
407
|
end
|
285
408
|
|
286
409
|
def environment_title_prefix
|
287
|
-
environment = Sidekiq.
|
410
|
+
environment = Sidekiq.default_configuration[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
288
411
|
|
289
412
|
"[#{environment.upcase}] " unless environment == "production"
|
290
413
|
end
|
@@ -294,30 +417,28 @@ module Sidekiq
|
|
294
417
|
end
|
295
418
|
|
296
419
|
def server_utc_time
|
297
|
-
Time.now.utc.strftime(
|
420
|
+
Time.now.utc.strftime("%H:%M:%S UTC")
|
298
421
|
end
|
299
422
|
|
300
|
-
def
|
301
|
-
|
302
|
-
|
303
|
-
"#{redis_connection}#{namespace_suffix}"
|
304
|
-
end
|
423
|
+
def pollable?
|
424
|
+
# there's no point to refreshing the metrics pages every N seconds
|
425
|
+
!(current_path == "" || current_path.index("metrics"))
|
305
426
|
end
|
306
427
|
|
307
428
|
def retry_or_delete_or_kill(job, params)
|
308
|
-
if params[
|
429
|
+
if params["retry"]
|
309
430
|
job.retry
|
310
|
-
elsif params[
|
431
|
+
elsif params["delete"]
|
311
432
|
job.delete
|
312
|
-
elsif params[
|
433
|
+
elsif params["kill"]
|
313
434
|
job.kill
|
314
435
|
end
|
315
436
|
end
|
316
437
|
|
317
438
|
def delete_or_add_queue(job, params)
|
318
|
-
if params[
|
439
|
+
if params["delete"]
|
319
440
|
job.delete
|
320
|
-
elsif params[
|
441
|
+
elsif params["add_to_queue"]
|
321
442
|
job.add_to_queue
|
322
443
|
end
|
323
444
|
end
|