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