sidekiq 5.2.9 → 6.1.2
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/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
- data/.github/workflows/ci.yml +41 -0
- data/.gitignore +0 -2
- data/.standard.yml +20 -0
- data/6.0-Upgrade.md +72 -0
- data/Changes.md +184 -0
- data/Ent-2.0-Upgrade.md +37 -0
- data/Ent-Changes.md +44 -1
- data/Gemfile +12 -11
- data/Gemfile.lock +192 -0
- data/Pro-5.0-Upgrade.md +25 -0
- data/Pro-Changes.md +48 -2
- data/README.md +18 -34
- data/Rakefile +5 -4
- data/bin/sidekiq +26 -2
- data/bin/sidekiqload +32 -24
- data/bin/sidekiqmon +8 -0
- data/lib/generators/sidekiq/templates/worker_test.rb.erb +1 -1
- data/lib/generators/sidekiq/worker_generator.rb +21 -13
- data/lib/sidekiq/api.rb +242 -219
- data/lib/sidekiq/cli.rb +131 -180
- data/lib/sidekiq/client.rb +67 -47
- data/lib/sidekiq/delay.rb +5 -6
- data/lib/sidekiq/exception_handler.rb +10 -12
- data/lib/sidekiq/extensions/action_mailer.rb +13 -22
- data/lib/sidekiq/extensions/active_record.rb +13 -10
- data/lib/sidekiq/extensions/class_methods.rb +14 -11
- data/lib/sidekiq/extensions/generic_proxy.rb +4 -4
- data/lib/sidekiq/fetch.rb +29 -30
- data/lib/sidekiq/job_logger.rb +45 -7
- data/lib/sidekiq/job_retry.rb +61 -61
- data/lib/sidekiq/launcher.rb +88 -55
- data/lib/sidekiq/logger.rb +165 -0
- data/lib/sidekiq/manager.rb +11 -13
- data/lib/sidekiq/middleware/chain.rb +15 -5
- data/lib/sidekiq/middleware/i18n.rb +5 -7
- data/lib/sidekiq/monitor.rb +133 -0
- data/lib/sidekiq/paginator.rb +18 -14
- data/lib/sidekiq/processor.rb +71 -70
- data/lib/sidekiq/rails.rb +29 -37
- data/lib/sidekiq/redis_connection.rb +50 -48
- data/lib/sidekiq/scheduled.rb +28 -29
- data/lib/sidekiq/sd_notify.rb +149 -0
- data/lib/sidekiq/systemd.rb +24 -0
- data/lib/sidekiq/testing/inline.rb +2 -1
- data/lib/sidekiq/testing.rb +35 -24
- data/lib/sidekiq/util.rb +17 -16
- data/lib/sidekiq/version.rb +2 -1
- data/lib/sidekiq/web/action.rb +14 -10
- data/lib/sidekiq/web/application.rb +73 -71
- data/lib/sidekiq/web/csrf_protection.rb +158 -0
- data/lib/sidekiq/web/helpers.rb +85 -77
- data/lib/sidekiq/web/router.rb +18 -17
- data/lib/sidekiq/web.rb +53 -53
- data/lib/sidekiq/worker.rb +126 -102
- data/lib/sidekiq.rb +69 -44
- data/sidekiq.gemspec +15 -16
- data/web/assets/javascripts/application.js +25 -27
- data/web/assets/javascripts/dashboard.js +4 -23
- data/web/assets/stylesheets/application-dark.css +143 -0
- data/web/assets/stylesheets/application.css +16 -6
- data/web/locales/de.yml +14 -2
- data/web/locales/en.yml +2 -0
- data/web/locales/fr.yml +2 -2
- data/web/locales/ja.yml +4 -1
- data/web/locales/lt.yml +83 -0
- data/web/locales/pl.yml +4 -4
- data/web/locales/ru.yml +4 -0
- data/web/locales/vi.yml +83 -0
- data/web/views/_job_info.erb +2 -1
- data/web/views/busy.erb +6 -3
- data/web/views/dead.erb +2 -2
- data/web/views/layout.erb +1 -0
- data/web/views/morgue.erb +5 -2
- data/web/views/queue.erb +10 -1
- data/web/views/queues.erb +9 -1
- data/web/views/retries.erb +5 -2
- data/web/views/retry.erb +2 -2
- data/web/views/scheduled.erb +5 -2
- metadata +25 -43
- data/.circleci/config.yml +0 -61
- data/.github/issue_template.md +0 -11
- data/.travis.yml +0 -11
- data/bin/sidekiqctl +0 -20
- data/lib/sidekiq/core_ext.rb +0 -1
- data/lib/sidekiq/ctl.rb +0 -221
- data/lib/sidekiq/logging.rb +0 -122
- data/lib/sidekiq/middleware/server/active_record.rb +0 -23
data/lib/sidekiq/web/helpers.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
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
|
# This is not a public API
|
9
10
|
module WebHelpers
|
10
11
|
def strings(lang)
|
11
|
-
|
12
|
-
|
12
|
+
@strings ||= {}
|
13
|
+
@strings[lang] ||= begin
|
13
14
|
# Allow sidekiq-web extensions to add locale paths
|
14
15
|
# so extensions can be localized
|
15
16
|
settings.locales.each_with_object({}) do |path, global|
|
@@ -22,19 +23,19 @@ module Sidekiq
|
|
22
23
|
end
|
23
24
|
|
24
25
|
def clear_caches
|
25
|
-
|
26
|
-
|
27
|
-
|
26
|
+
@strings = nil
|
27
|
+
@locale_files = nil
|
28
|
+
@available_locales = nil
|
28
29
|
end
|
29
30
|
|
30
31
|
def locale_files
|
31
|
-
|
32
|
+
@locale_files ||= settings.locales.flat_map { |path|
|
32
33
|
Dir["#{path}/*.yml"]
|
33
|
-
|
34
|
+
}
|
34
35
|
end
|
35
36
|
|
36
37
|
def available_locales
|
37
|
-
|
38
|
+
@available_locales ||= locale_files.map { |path| File.basename(path, ".yml") }.uniq
|
38
39
|
end
|
39
40
|
|
40
41
|
def find_locale_files(lang)
|
@@ -63,32 +64,35 @@ module Sidekiq
|
|
63
64
|
end
|
64
65
|
|
65
66
|
def poll_path
|
66
|
-
if current_path !=
|
67
|
-
root_path + current_path
|
67
|
+
if current_path != "" && params["poll"]
|
68
|
+
path = root_path + current_path
|
69
|
+
query_string = to_query_string(params.slice(*params.keys - %w[page poll]))
|
70
|
+
path += "?#{query_string}" unless query_string.empty?
|
71
|
+
path
|
68
72
|
else
|
69
73
|
""
|
70
74
|
end
|
71
75
|
end
|
72
76
|
|
73
77
|
def text_direction
|
74
|
-
get_locale[
|
78
|
+
get_locale["TextDirection"] || "ltr"
|
75
79
|
end
|
76
80
|
|
77
81
|
def rtl?
|
78
|
-
text_direction ==
|
82
|
+
text_direction == "rtl"
|
79
83
|
end
|
80
84
|
|
81
85
|
# See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
|
82
86
|
def user_preferred_languages
|
83
|
-
languages = env[
|
84
|
-
languages.to_s.downcase.gsub(/\s+/,
|
85
|
-
locale, quality = language.split(
|
86
|
-
locale
|
87
|
+
languages = env["HTTP_ACCEPT_LANGUAGE"]
|
88
|
+
languages.to_s.downcase.gsub(/\s+/, "").split(",").map { |language|
|
89
|
+
locale, quality = language.split(";q=", 2)
|
90
|
+
locale = nil if locale == "*" # Ignore wildcards
|
87
91
|
quality = quality ? quality.to_f : 1.0
|
88
92
|
[locale, quality]
|
89
|
-
|
93
|
+
}.sort { |(_, left), (_, right)|
|
90
94
|
right <=> left
|
91
|
-
|
95
|
+
}.map(&:first).compact
|
92
96
|
end
|
93
97
|
|
94
98
|
# 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"
|
@@ -97,31 +101,38 @@ module Sidekiq
|
|
97
101
|
# Inspiration taken from https://github.com/iain/http_accept_language/blob/master/lib/http_accept_language/parser.rb
|
98
102
|
def locale
|
99
103
|
@locale ||= begin
|
100
|
-
matched_locale = user_preferred_languages.map
|
101
|
-
preferred_language = preferred.split(
|
104
|
+
matched_locale = user_preferred_languages.map { |preferred|
|
105
|
+
preferred_language = preferred.split("-", 2).first
|
102
106
|
|
103
|
-
lang_group = available_locales.select
|
104
|
-
preferred_language == available.split(
|
105
|
-
|
107
|
+
lang_group = available_locales.select { |available|
|
108
|
+
preferred_language == available.split("-", 2).first
|
109
|
+
}
|
106
110
|
|
107
111
|
lang_group.find { |lang| lang == preferred } || lang_group.min_by(&:length)
|
108
|
-
|
112
|
+
}.compact.first
|
109
113
|
|
110
|
-
matched_locale ||
|
114
|
+
matched_locale || "en"
|
111
115
|
end
|
112
116
|
end
|
113
117
|
|
118
|
+
# within is used by Sidekiq Pro
|
119
|
+
def display_tags(job, within = nil)
|
120
|
+
job.tags.map { |tag|
|
121
|
+
"<span class='jobtag label label-info'>#{::Rack::Utils.escape_html(tag)}</span>"
|
122
|
+
}.join(" ")
|
123
|
+
end
|
124
|
+
|
114
125
|
# mperham/sidekiq#3243
|
115
126
|
def unfiltered?
|
116
|
-
yield unless env[
|
127
|
+
yield unless env["PATH_INFO"].start_with?("/filter/")
|
117
128
|
end
|
118
129
|
|
119
130
|
def get_locale
|
120
131
|
strings(locale)
|
121
132
|
end
|
122
133
|
|
123
|
-
def t(msg, options={})
|
124
|
-
string = get_locale[msg] || strings(
|
134
|
+
def t(msg, options = {})
|
135
|
+
string = get_locale[msg] || strings("en")[msg] || msg
|
125
136
|
if options.empty?
|
126
137
|
string
|
127
138
|
else
|
@@ -129,6 +140,10 @@ module Sidekiq
|
|
129
140
|
end
|
130
141
|
end
|
131
142
|
|
143
|
+
def sort_direction_label
|
144
|
+
params[:direction] == "asc" ? "↑" : "↓"
|
145
|
+
end
|
146
|
+
|
132
147
|
def workers
|
133
148
|
@workers ||= Sidekiq::Workers.new
|
134
149
|
end
|
@@ -141,12 +156,6 @@ module Sidekiq
|
|
141
156
|
@stats ||= Sidekiq::Stats.new
|
142
157
|
end
|
143
158
|
|
144
|
-
def retries_with_score(score)
|
145
|
-
Sidekiq.redis do |conn|
|
146
|
-
conn.zrangebyscore('retry', score, score)
|
147
|
-
end.map { |msg| Sidekiq.load_json(msg) }
|
148
|
-
end
|
149
|
-
|
150
159
|
def redis_connection
|
151
160
|
Sidekiq.redis do |conn|
|
152
161
|
c = conn.connection
|
@@ -163,24 +172,24 @@ module Sidekiq
|
|
163
172
|
end
|
164
173
|
|
165
174
|
def root_path
|
166
|
-
"#{env[
|
175
|
+
"#{env["SCRIPT_NAME"]}/"
|
167
176
|
end
|
168
177
|
|
169
178
|
def current_path
|
170
|
-
@current_path ||= request.path_info.gsub(/^\//,
|
179
|
+
@current_path ||= request.path_info.gsub(/^\//, "")
|
171
180
|
end
|
172
181
|
|
173
182
|
def current_status
|
174
|
-
workers.size == 0 ?
|
183
|
+
workers.size == 0 ? "idle" : "active"
|
175
184
|
end
|
176
185
|
|
177
186
|
def relative_time(time)
|
178
187
|
stamp = time.getutc.iso8601
|
179
|
-
%
|
188
|
+
%(<time class="ltr" dir="ltr" title="#{stamp}" datetime="#{stamp}">#{time}</time>)
|
180
189
|
end
|
181
190
|
|
182
191
|
def job_params(job, score)
|
183
|
-
"#{score}-#{job[
|
192
|
+
"#{score}-#{job["jid"]}"
|
184
193
|
end
|
185
194
|
|
186
195
|
def parse_params(params)
|
@@ -188,18 +197,19 @@ module Sidekiq
|
|
188
197
|
[score.to_f, jid]
|
189
198
|
end
|
190
199
|
|
191
|
-
SAFE_QPARAMS = %w
|
200
|
+
SAFE_QPARAMS = %w[page poll direction]
|
192
201
|
|
193
202
|
# Merge options with current params, filter safe params, and stringify to query string
|
194
203
|
def qparams(options)
|
195
|
-
|
196
|
-
options.keys.each do |key|
|
197
|
-
options[key.to_s] = options.delete(key)
|
198
|
-
end
|
204
|
+
stringified_options = options.transform_keys(&:to_s)
|
199
205
|
|
200
|
-
params.merge(
|
206
|
+
to_query_string(params.merge(stringified_options))
|
207
|
+
end
|
208
|
+
|
209
|
+
def to_query_string(params)
|
210
|
+
params.map { |key, value|
|
201
211
|
SAFE_QPARAMS.include?(key) ? "#{key}=#{CGI.escape(value.to_s)}" : next
|
202
|
-
|
212
|
+
}.compact.join("&")
|
203
213
|
end
|
204
214
|
|
205
215
|
def truncate(text, truncate_after_chars = 2000)
|
@@ -207,40 +217,38 @@ module Sidekiq
|
|
207
217
|
end
|
208
218
|
|
209
219
|
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}"
|
220
|
+
return "Invalid job payload, args is nil" if args.nil?
|
221
|
+
return "Invalid job payload, args must be an Array, not #{args.class.name}" unless args.is_a?(Array)
|
212
222
|
|
213
223
|
begin
|
214
|
-
args.map
|
224
|
+
args.map { |arg|
|
215
225
|
h(truncate(to_display(arg), truncate_after_chars))
|
216
|
-
|
226
|
+
}.join(", ")
|
217
227
|
rescue
|
218
228
|
"Illegal job arguments: #{h args.inspect}"
|
219
229
|
end
|
220
230
|
end
|
221
231
|
|
222
232
|
def csrf_tag
|
223
|
-
"<input type='hidden' name='authenticity_token' value='#{
|
233
|
+
"<input type='hidden' name='authenticity_token' value='#{env[:csrf_token]}'/>"
|
224
234
|
end
|
225
235
|
|
226
236
|
def to_display(arg)
|
237
|
+
arg.inspect
|
238
|
+
rescue
|
227
239
|
begin
|
228
|
-
arg.
|
229
|
-
rescue
|
230
|
-
|
231
|
-
arg.to_s
|
232
|
-
rescue => ex
|
233
|
-
"Cannot display argument: [#{ex.class.name}] #{ex.message}"
|
234
|
-
end
|
240
|
+
arg.to_s
|
241
|
+
rescue => ex
|
242
|
+
"Cannot display argument: [#{ex.class.name}] #{ex.message}"
|
235
243
|
end
|
236
244
|
end
|
237
245
|
|
238
|
-
RETRY_JOB_KEYS = Set.new(%w
|
246
|
+
RETRY_JOB_KEYS = Set.new(%w[
|
239
247
|
queue class args retry_count retried_at failed_at
|
240
248
|
jid error_message error_class backtrace
|
241
249
|
error_backtrace enqueued_at retry wrapped
|
242
|
-
created_at
|
243
|
-
)
|
250
|
+
created_at tags
|
251
|
+
])
|
244
252
|
|
245
253
|
def retry_extra_items(retry_job)
|
246
254
|
@retry_extra_items ||= {}.tap do |extra|
|
@@ -257,8 +265,8 @@ module Sidekiq
|
|
257
265
|
return number
|
258
266
|
end
|
259
267
|
|
260
|
-
options = {delimiter:
|
261
|
-
parts = number.to_s.to_str.split(
|
268
|
+
options = {delimiter: ",", separator: "."}
|
269
|
+
parts = number.to_s.to_str.split(".")
|
262
270
|
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
|
263
271
|
parts.join(options[:separator])
|
264
272
|
end
|
@@ -266,8 +274,8 @@ module Sidekiq
|
|
266
274
|
def h(text)
|
267
275
|
::Rack::Utils.escape_html(text)
|
268
276
|
rescue ArgumentError => e
|
269
|
-
raise unless e.message.eql?(
|
270
|
-
text.encode!(
|
277
|
+
raise unless e.message.eql?("invalid byte sequence in UTF-8")
|
278
|
+
text.encode!("UTF-16", "UTF-8", invalid: :replace, replace: "").encode!("UTF-8", "UTF-16")
|
271
279
|
retry
|
272
280
|
end
|
273
281
|
|
@@ -284,7 +292,7 @@ module Sidekiq
|
|
284
292
|
end
|
285
293
|
|
286
294
|
def environment_title_prefix
|
287
|
-
environment = Sidekiq.options[:environment] || ENV[
|
295
|
+
environment = Sidekiq.options[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
288
296
|
|
289
297
|
"[#{environment.upcase}] " unless environment == "production"
|
290
298
|
end
|
@@ -294,30 +302,30 @@ module Sidekiq
|
|
294
302
|
end
|
295
303
|
|
296
304
|
def server_utc_time
|
297
|
-
Time.now.utc.strftime(
|
305
|
+
Time.now.utc.strftime("%H:%M:%S UTC")
|
298
306
|
end
|
299
307
|
|
300
308
|
def redis_connection_and_namespace
|
301
309
|
@redis_connection_and_namespace ||= begin
|
302
|
-
namespace_suffix = namespace
|
310
|
+
namespace_suffix = namespace.nil? ? "" : "##{namespace}"
|
303
311
|
"#{redis_connection}#{namespace_suffix}"
|
304
312
|
end
|
305
313
|
end
|
306
314
|
|
307
315
|
def retry_or_delete_or_kill(job, params)
|
308
|
-
if params[
|
316
|
+
if params["retry"]
|
309
317
|
job.retry
|
310
|
-
elsif params[
|
318
|
+
elsif params["delete"]
|
311
319
|
job.delete
|
312
|
-
elsif params[
|
320
|
+
elsif params["kill"]
|
313
321
|
job.kill
|
314
322
|
end
|
315
323
|
end
|
316
324
|
|
317
325
|
def delete_or_add_queue(job, params)
|
318
|
-
if params[
|
326
|
+
if params["delete"]
|
319
327
|
job.delete
|
320
|
-
elsif params[
|
328
|
+
elsif params["add_to_queue"]
|
321
329
|
job.add_to_queue
|
322
330
|
end
|
323
331
|
end
|
data/lib/sidekiq/web/router.rb
CHANGED
@@ -1,18 +1,19 @@
|
|
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 =
|
7
|
+
GET = "GET"
|
8
|
+
DELETE = "DELETE"
|
9
|
+
POST = "POST"
|
10
|
+
PUT = "PUT"
|
11
|
+
PATCH = "PATCH"
|
12
|
+
HEAD = "HEAD"
|
12
13
|
|
13
|
-
ROUTE_PARAMS =
|
14
|
-
REQUEST_METHOD =
|
15
|
-
PATH_INFO =
|
14
|
+
ROUTE_PARAMS = "rack.route_params"
|
15
|
+
REQUEST_METHOD = "REQUEST_METHOD"
|
16
|
+
PATH_INFO = "PATH_INFO"
|
16
17
|
|
17
18
|
def get(path, &block)
|
18
19
|
route(GET, path, &block)
|
@@ -35,7 +36,7 @@ module Sidekiq
|
|
35
36
|
end
|
36
37
|
|
37
38
|
def route(method, path, &block)
|
38
|
-
@routes ||= {
|
39
|
+
@routes ||= {GET => [], POST => [], PUT => [], PATCH => [], DELETE => [], HEAD => []}
|
39
40
|
|
40
41
|
@routes[method] << WebRoute.new(method, path, block)
|
41
42
|
@routes[HEAD] << WebRoute.new(method, path, block) if method == GET
|
@@ -50,7 +51,8 @@ module Sidekiq
|
|
50
51
|
path_info = "/" if path_info == ""
|
51
52
|
|
52
53
|
@routes[request_method].each do |route|
|
53
|
-
|
54
|
+
params = route.match(request_method, path_info)
|
55
|
+
if params
|
54
56
|
env[ROUTE_PARAMS] = params
|
55
57
|
|
56
58
|
return WebAction.new(env, route.block)
|
@@ -64,7 +66,7 @@ module Sidekiq
|
|
64
66
|
class WebRoute
|
65
67
|
attr_accessor :request_method, :pattern, :block, :name
|
66
68
|
|
67
|
-
NAMED_SEGMENTS_PATTERN = /\/([^\/]*):([
|
69
|
+
NAMED_SEGMENTS_PATTERN = /\/([^\/]*):([^.:$\/]+)/
|
68
70
|
|
69
71
|
def initialize(request_method, pattern, block)
|
70
72
|
@request_method = request_method
|
@@ -77,7 +79,7 @@ module Sidekiq
|
|
77
79
|
end
|
78
80
|
|
79
81
|
def compile
|
80
|
-
if pattern.match(NAMED_SEGMENTS_PATTERN)
|
82
|
+
if pattern.match?(NAMED_SEGMENTS_PATTERN)
|
81
83
|
p = pattern.gsub(NAMED_SEGMENTS_PATTERN, '/\1(?<\2>[^$/]+)')
|
82
84
|
|
83
85
|
Regexp.new("\\A#{p}\\Z")
|
@@ -91,9 +93,8 @@ module Sidekiq
|
|
91
93
|
when String
|
92
94
|
{} if path == matcher
|
93
95
|
else
|
94
|
-
|
95
|
-
|
96
|
-
end
|
96
|
+
path_match = path.match(matcher)
|
97
|
+
path_match&.named_captures&.transform_keys(&:to_sym)
|
97
98
|
end
|
98
99
|
end
|
99
100
|
end
|
data/lib/sidekiq/web.rb
CHANGED
@@ -1,20 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'erb'
|
3
2
|
|
4
|
-
require
|
5
|
-
require 'sidekiq/api'
|
6
|
-
require 'sidekiq/paginator'
|
7
|
-
require 'sidekiq/web/helpers'
|
3
|
+
require "erb"
|
8
4
|
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
5
|
+
require "sidekiq"
|
6
|
+
require "sidekiq/api"
|
7
|
+
require "sidekiq/paginator"
|
8
|
+
require "sidekiq/web/helpers"
|
12
9
|
|
13
|
-
require
|
10
|
+
require "sidekiq/web/router"
|
11
|
+
require "sidekiq/web/action"
|
12
|
+
require "sidekiq/web/application"
|
13
|
+
require "sidekiq/web/csrf_protection"
|
14
14
|
|
15
|
-
require
|
16
|
-
|
17
|
-
require
|
15
|
+
require "rack/content_length"
|
16
|
+
|
17
|
+
require "rack/builder"
|
18
|
+
require "rack/file"
|
19
|
+
require "rack/session/cookie"
|
18
20
|
|
19
21
|
module Sidekiq
|
20
22
|
class Web
|
@@ -25,12 +27,12 @@ module Sidekiq
|
|
25
27
|
ASSETS = "#{ROOT}/assets"
|
26
28
|
|
27
29
|
DEFAULT_TABS = {
|
28
|
-
"Dashboard" =>
|
29
|
-
"Busy"
|
30
|
-
"Queues"
|
31
|
-
"Retries"
|
32
|
-
"Scheduled" =>
|
33
|
-
"Dead"
|
30
|
+
"Dashboard" => "",
|
31
|
+
"Busy" => "busy",
|
32
|
+
"Queues" => "queues",
|
33
|
+
"Retries" => "retries",
|
34
|
+
"Scheduled" => "scheduled",
|
35
|
+
"Dead" => "morgue"
|
34
36
|
}
|
35
37
|
|
36
38
|
class << self
|
@@ -64,11 +66,11 @@ module Sidekiq
|
|
64
66
|
end
|
65
67
|
|
66
68
|
def enable(*opts)
|
67
|
-
opts.each {|key| set(key, true) }
|
69
|
+
opts.each { |key| set(key, true) }
|
68
70
|
end
|
69
71
|
|
70
72
|
def disable(*opts)
|
71
|
-
opts.each {|key| set(key, false) }
|
73
|
+
opts.each { |key| set(key, false) }
|
72
74
|
end
|
73
75
|
|
74
76
|
# Helper for the Sinatra syntax: Sidekiq::Web.set(:session_secret, Rails.application.secrets...)
|
@@ -81,10 +83,10 @@ module Sidekiq
|
|
81
83
|
end
|
82
84
|
|
83
85
|
def self.inherited(child)
|
84
|
-
child.app_url =
|
85
|
-
child.session_secret =
|
86
|
-
child.redis_pool =
|
87
|
-
child.sessions =
|
86
|
+
child.app_url = app_url
|
87
|
+
child.session_secret = session_secret
|
88
|
+
child.redis_pool = redis_pool
|
89
|
+
child.sessions = sessions
|
88
90
|
end
|
89
91
|
|
90
92
|
def settings
|
@@ -113,11 +115,11 @@ module Sidekiq
|
|
113
115
|
end
|
114
116
|
|
115
117
|
def enable(*opts)
|
116
|
-
opts.each {|key| set(key, true) }
|
118
|
+
opts.each { |key| set(key, true) }
|
117
119
|
end
|
118
120
|
|
119
121
|
def disable(*opts)
|
120
|
-
opts.each {|key| set(key, false) }
|
122
|
+
opts.each { |key| set(key, false) }
|
121
123
|
end
|
122
124
|
|
123
125
|
def set(attribute, value)
|
@@ -145,32 +147,39 @@ module Sidekiq
|
|
145
147
|
private
|
146
148
|
|
147
149
|
def using?(middleware)
|
148
|
-
middlewares.any? do |(m,_)|
|
149
|
-
m.
|
150
|
+
middlewares.any? do |(m, _)|
|
151
|
+
m.is_a?(Array) && (m[0] == middleware || m[0].is_a?(middleware))
|
150
152
|
end
|
151
153
|
end
|
152
154
|
|
153
155
|
def build_sessions
|
154
156
|
middlewares = self.middlewares
|
155
157
|
|
156
|
-
unless using?(::Rack::Protection) || ENV['RACK_ENV'] == 'test'
|
157
|
-
middlewares.unshift [[::Rack::Protection, { use: :authenticity_token }], nil]
|
158
|
-
end
|
159
|
-
|
160
158
|
s = sessions
|
161
|
-
return unless s
|
162
159
|
|
163
|
-
|
164
|
-
|
165
|
-
|
160
|
+
# turn on CSRF protection if sessions are enabled and this is not the test env
|
161
|
+
if s && !using?(CsrfProtection) && ENV["RACK_ENV"] != "test"
|
162
|
+
middlewares.unshift [[CsrfProtection], nil]
|
163
|
+
end
|
164
|
+
|
165
|
+
if s && !using?(::Rack::Session::Cookie)
|
166
|
+
unless (secret = Web.session_secret)
|
167
|
+
require "securerandom"
|
166
168
|
secret = SecureRandom.hex(64)
|
167
169
|
end
|
168
170
|
|
169
|
-
options = {
|
171
|
+
options = {secret: secret}
|
170
172
|
options = options.merge(s.to_hash) if s.respond_to? :to_hash
|
171
173
|
|
172
174
|
middlewares.unshift [[::Rack::Session::Cookie, options], nil]
|
173
175
|
end
|
176
|
+
|
177
|
+
# Since Sidekiq::WebApplication no longer calculates its own
|
178
|
+
# Content-Length response header, we must ensure that the Rack middleware
|
179
|
+
# that does this is loaded
|
180
|
+
unless using? ::Rack::ContentLength
|
181
|
+
middlewares.unshift [[::Rack::ContentLength], nil]
|
182
|
+
end
|
174
183
|
end
|
175
184
|
|
176
185
|
def build
|
@@ -180,13 +189,13 @@ module Sidekiq
|
|
180
189
|
klass = self.class
|
181
190
|
|
182
191
|
::Rack::Builder.new do
|
183
|
-
%w
|
192
|
+
%w[stylesheets javascripts images].each do |asset_dir|
|
184
193
|
map "/#{asset_dir}" do
|
185
|
-
run ::Rack::File.new("#{ASSETS}/#{asset_dir}", {
|
194
|
+
run ::Rack::File.new("#{ASSETS}/#{asset_dir}", {"Cache-Control" => "public, max-age=86400"})
|
186
195
|
end
|
187
196
|
end
|
188
197
|
|
189
|
-
middlewares.each {|middleware, block| use(*middleware, &block) }
|
198
|
+
middlewares.each { |middleware, block| use(*middleware, &block) }
|
190
199
|
|
191
200
|
run WebApplication.new(klass)
|
192
201
|
end
|
@@ -196,18 +205,9 @@ module Sidekiq
|
|
196
205
|
Sidekiq::WebApplication.helpers WebHelpers
|
197
206
|
Sidekiq::WebApplication.helpers Sidekiq::Paginator
|
198
207
|
|
199
|
-
Sidekiq::WebAction.class_eval
|
200
|
-
|
201
|
-
|
202
|
-
if defined?(::ActionDispatch::Request::Session) &&
|
203
|
-
!::ActionDispatch::Request::Session.method_defined?(:each)
|
204
|
-
# mperham/sidekiq#2460
|
205
|
-
# Rack apps can't reuse the Rails session store without
|
206
|
-
# this monkeypatch, fixed in Rails 5.
|
207
|
-
class ActionDispatch::Request::Session
|
208
|
-
def each(&block)
|
209
|
-
hash = self.to_hash
|
210
|
-
hash.each(&block)
|
208
|
+
Sidekiq::WebAction.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
209
|
+
def _render
|
210
|
+
#{ERB.new(File.read(Web::LAYOUT)).src}
|
211
211
|
end
|
212
|
-
|
212
|
+
RUBY
|
213
213
|
end
|