sidekiq 4.2.10 → 6.5.7
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 +5 -5
- data/Changes.md +573 -1
- data/LICENSE +3 -3
- data/README.md +25 -34
- data/bin/sidekiq +27 -3
- data/bin/sidekiqload +81 -74
- data/bin/sidekiqmon +8 -0
- data/lib/generators/sidekiq/job_generator.rb +57 -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 +585 -285
- data/lib/sidekiq/cli.rb +256 -233
- data/lib/sidekiq/client.rb +86 -83
- data/lib/sidekiq/component.rb +65 -0
- data/lib/sidekiq/delay.rb +43 -0
- 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 +13 -5
- data/lib/sidekiq/fetch.rb +50 -40
- data/lib/sidekiq/job.rb +13 -0
- data/lib/sidekiq/job_logger.rb +51 -0
- data/lib/sidekiq/job_retry.rb +282 -0
- data/lib/sidekiq/job_util.rb +71 -0
- data/lib/sidekiq/launcher.rb +184 -90
- data/lib/sidekiq/logger.rb +156 -0
- data/lib/sidekiq/manager.rb +43 -45
- data/lib/sidekiq/metrics/deploy.rb +47 -0
- data/lib/sidekiq/metrics/query.rb +153 -0
- data/lib/sidekiq/metrics/shared.rb +94 -0
- data/lib/sidekiq/metrics/tracking.rb +134 -0
- data/lib/sidekiq/middleware/chain.rb +102 -46
- data/lib/sidekiq/middleware/current_attributes.rb +63 -0
- data/lib/sidekiq/middleware/i18n.rb +7 -7
- data/lib/sidekiq/middleware/modules.rb +21 -0
- data/lib/sidekiq/monitor.rb +133 -0
- data/lib/sidekiq/paginator.rb +20 -16
- data/lib/sidekiq/processor.rb +176 -91
- data/lib/sidekiq/rails.rb +41 -96
- data/lib/sidekiq/redis_client_adapter.rb +154 -0
- data/lib/sidekiq/redis_connection.rb +117 -48
- data/lib/sidekiq/ring_buffer.rb +29 -0
- data/lib/sidekiq/scheduled.rb +134 -44
- data/lib/sidekiq/sd_notify.rb +149 -0
- data/lib/sidekiq/systemd.rb +24 -0
- data/lib/sidekiq/testing/inline.rb +6 -5
- data/lib/sidekiq/testing.rb +80 -61
- data/lib/sidekiq/transaction_aware_client.rb +45 -0
- data/lib/sidekiq/version.rb +2 -1
- data/lib/sidekiq/web/action.rb +15 -15
- data/lib/sidekiq/web/application.rb +129 -86
- data/lib/sidekiq/web/csrf_protection.rb +180 -0
- data/lib/sidekiq/web/helpers.rb +170 -83
- data/lib/sidekiq/web/router.rb +23 -19
- data/lib/sidekiq/web.rb +69 -109
- data/lib/sidekiq/worker.rb +290 -41
- data/lib/sidekiq.rb +185 -77
- data/sidekiq.gemspec +23 -27
- data/web/assets/images/apple-touch-icon.png +0 -0
- data/web/assets/javascripts/application.js +112 -61
- 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.js +70 -91
- data/web/assets/javascripts/graph.js +16 -0
- data/web/assets/javascripts/metrics.js +262 -0
- data/web/assets/stylesheets/application-dark.css +143 -0
- data/web/assets/stylesheets/application-rtl.css +242 -0
- data/web/assets/stylesheets/application.css +364 -144
- 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/de.yml +14 -2
- data/web/locales/el.yml +43 -19
- data/web/locales/en.yml +15 -1
- data/web/locales/es.yml +22 -5
- data/web/locales/fa.yml +1 -0
- data/web/locales/fr.yml +10 -3
- data/web/locales/he.yml +79 -0
- data/web/locales/ja.yml +19 -4
- data/web/locales/lt.yml +83 -0
- data/web/locales/pl.yml +4 -4
- data/web/locales/pt-br.yml +27 -9
- data/web/locales/ru.yml +4 -0
- data/web/locales/ur.yml +80 -0
- data/web/locales/vi.yml +83 -0
- data/web/locales/zh-cn.yml +36 -11
- data/web/locales/zh-tw.yml +32 -7
- data/web/views/_footer.erb +5 -2
- data/web/views/_job_info.erb +3 -2
- data/web/views/_nav.erb +5 -19
- data/web/views/_paging.erb +1 -1
- data/web/views/_poll_link.erb +2 -5
- data/web/views/_summary.erb +7 -7
- data/web/views/busy.erb +62 -24
- data/web/views/dashboard.erb +24 -15
- data/web/views/dead.erb +3 -3
- data/web/views/layout.erb +14 -3
- data/web/views/metrics.erb +69 -0
- data/web/views/metrics_for_job.erb +87 -0
- data/web/views/morgue.erb +9 -6
- data/web/views/queue.erb +26 -12
- data/web/views/queues.erb +12 -2
- data/web/views/retries.erb +14 -7
- data/web/views/retry.erb +3 -3
- data/web/views/scheduled.erb +7 -4
- metadata +66 -206
- 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/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/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/web/helpers.rb
CHANGED
@@ -1,35 +1,48 @@
|
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
12
|
+
@strings ||= {}
|
13
|
+
|
14
|
+
# Allow sidekiq-web extensions to add locale paths
|
15
|
+
# so extensions can be localized
|
16
|
+
@strings[lang] ||= settings.locales.each_with_object({}) do |path, global|
|
17
|
+
find_locale_files(lang).each do |file|
|
18
|
+
strs = YAML.safe_load(File.open(file))
|
19
|
+
global.merge!(strs[lang])
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
def singularize(str, count)
|
25
|
+
if count == 1 && str.respond_to?(:singularize) # rails
|
26
|
+
str.singularize
|
27
|
+
else
|
28
|
+
str
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
24
32
|
def clear_caches
|
25
|
-
|
26
|
-
|
33
|
+
@strings = nil
|
34
|
+
@locale_files = nil
|
35
|
+
@available_locales = nil
|
27
36
|
end
|
28
37
|
|
29
38
|
def locale_files
|
30
|
-
|
39
|
+
@locale_files ||= settings.locales.flat_map { |path|
|
31
40
|
Dir["#{path}/*.yml"]
|
32
|
-
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def available_locales
|
45
|
+
@available_locales ||= locale_files.map { |path| File.basename(path, ".yml") }.uniq
|
33
46
|
end
|
34
47
|
|
35
48
|
def find_locale_files(lang)
|
@@ -57,42 +70,65 @@ module Sidekiq
|
|
57
70
|
@head_html.join if defined?(@head_html)
|
58
71
|
end
|
59
72
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
73
|
+
def text_direction
|
74
|
+
get_locale["TextDirection"] || "ltr"
|
75
|
+
end
|
76
|
+
|
77
|
+
def rtl?
|
78
|
+
text_direction == "rtl"
|
79
|
+
end
|
80
|
+
|
81
|
+
# See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
|
82
|
+
def user_preferred_languages
|
83
|
+
languages = env["HTTP_ACCEPT_LANGUAGE"]
|
84
|
+
languages.to_s.downcase.gsub(/\s+/, "").split(",").map { |language|
|
85
|
+
locale, quality = language.split(";q=", 2)
|
86
|
+
locale = nil if locale == "*" # Ignore wildcards
|
87
|
+
quality = quality ? quality.to_f : 1.0
|
88
|
+
[locale, quality]
|
89
|
+
}.sort { |(_, left), (_, right)|
|
90
|
+
right <=> left
|
91
|
+
}.map(&:first).compact
|
66
92
|
end
|
67
93
|
|
68
|
-
# Given
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
94
|
+
# 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
|
+
# 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
|
72
98
|
def locale
|
73
99
|
@locale ||= begin
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
100
|
+
matched_locale = user_preferred_languages.map { |preferred|
|
101
|
+
preferred_language = preferred.split("-", 2).first
|
102
|
+
|
103
|
+
lang_group = available_locales.select { |available|
|
104
|
+
preferred_language == available.split("-", 2).first
|
105
|
+
}
|
106
|
+
|
107
|
+
lang_group.find { |lang| lang == preferred } || lang_group.min_by(&:length)
|
108
|
+
}.compact.first
|
109
|
+
|
110
|
+
matched_locale || "en"
|
82
111
|
end
|
83
112
|
end
|
84
113
|
|
114
|
+
# within is used by Sidekiq Pro
|
115
|
+
def display_tags(job, within = nil)
|
116
|
+
job.tags.map { |tag|
|
117
|
+
"<span class='label label-info jobtag'>#{::Rack::Utils.escape_html(tag)}</span>"
|
118
|
+
}.join(" ")
|
119
|
+
end
|
120
|
+
|
85
121
|
# mperham/sidekiq#3243
|
86
122
|
def unfiltered?
|
87
|
-
yield unless env[
|
123
|
+
yield unless env["PATH_INFO"].start_with?("/filter/")
|
88
124
|
end
|
89
125
|
|
90
126
|
def get_locale
|
91
127
|
strings(locale)
|
92
128
|
end
|
93
129
|
|
94
|
-
def t(msg, options={})
|
95
|
-
string = get_locale[msg] || msg
|
130
|
+
def t(msg, options = {})
|
131
|
+
string = get_locale[msg] || strings("en")[msg] || msg
|
96
132
|
if options.empty?
|
97
133
|
string
|
98
134
|
else
|
@@ -100,30 +136,53 @@ module Sidekiq
|
|
100
136
|
end
|
101
137
|
end
|
102
138
|
|
103
|
-
def
|
104
|
-
|
139
|
+
def sort_direction_label
|
140
|
+
params[:direction] == "asc" ? "↑" : "↓"
|
141
|
+
end
|
142
|
+
|
143
|
+
def workset
|
144
|
+
@work ||= Sidekiq::WorkSet.new
|
105
145
|
end
|
106
146
|
|
107
147
|
def processes
|
108
148
|
@processes ||= Sidekiq::ProcessSet.new
|
109
149
|
end
|
110
150
|
|
111
|
-
|
112
|
-
|
151
|
+
# Sorts processes by hostname following the natural sort order so that
|
152
|
+
# 'worker.1' < 'worker.2' < 'worker.10' < 'worker.20'
|
153
|
+
# '2.1.1.1' < '192.168.0.2' < '192.168.0.10'
|
154
|
+
def sorted_processes
|
155
|
+
@sorted_processes ||= begin
|
156
|
+
return processes unless processes.all? { |p| p["hostname"] }
|
157
|
+
|
158
|
+
split_characters = /[._-]+/
|
159
|
+
|
160
|
+
padding = processes.flat_map { |p| p["hostname"].split(split_characters) }.map(&:size).max
|
161
|
+
|
162
|
+
processes.to_a.sort_by do |process|
|
163
|
+
process["hostname"].split(split_characters).map do |substring|
|
164
|
+
# Left-pad the substring with '0' if it starts with a number or 'a'
|
165
|
+
# otherwise, so that '25' < 192' < 'a' ('025' < '192' < 'aaa')
|
166
|
+
padding_char = substring[0].match?(/\d/) ? "0" : "a"
|
167
|
+
|
168
|
+
substring.rjust(padding, padding_char)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
113
172
|
end
|
114
173
|
|
115
|
-
def
|
116
|
-
Sidekiq.
|
117
|
-
conn.zrangebyscore('retry', score, score)
|
118
|
-
end.map { |msg| Sidekiq.load_json(msg) }
|
174
|
+
def stats
|
175
|
+
@stats ||= Sidekiq::Stats.new
|
119
176
|
end
|
120
177
|
|
121
178
|
def redis_connection
|
122
|
-
Sidekiq.redis
|
179
|
+
Sidekiq.redis do |conn|
|
180
|
+
conn.connection[:id]
|
181
|
+
end
|
123
182
|
end
|
124
183
|
|
125
184
|
def namespace
|
126
|
-
|
185
|
+
@ns ||= Sidekiq.redis { |conn| conn.respond_to?(:namespace) ? conn.namespace : nil }
|
127
186
|
end
|
128
187
|
|
129
188
|
def redis_info
|
@@ -131,39 +190,44 @@ module Sidekiq
|
|
131
190
|
end
|
132
191
|
|
133
192
|
def root_path
|
134
|
-
"#{env[
|
193
|
+
"#{env["SCRIPT_NAME"]}/"
|
135
194
|
end
|
136
195
|
|
137
196
|
def current_path
|
138
|
-
@current_path ||= request.path_info.gsub(/^\//,
|
197
|
+
@current_path ||= request.path_info.gsub(/^\//, "")
|
139
198
|
end
|
140
199
|
|
141
200
|
def current_status
|
142
|
-
|
201
|
+
workset.size == 0 ? "idle" : "active"
|
143
202
|
end
|
144
203
|
|
145
204
|
def relative_time(time)
|
146
205
|
stamp = time.getutc.iso8601
|
147
|
-
%
|
206
|
+
%(<time class="ltr" dir="ltr" title="#{stamp}" datetime="#{stamp}">#{time}</time>)
|
148
207
|
end
|
149
208
|
|
150
209
|
def job_params(job, score)
|
151
|
-
"#{score}-#{job[
|
210
|
+
"#{score}-#{job["jid"]}"
|
152
211
|
end
|
153
212
|
|
154
213
|
def parse_params(params)
|
155
|
-
score, jid = params.split("-")
|
214
|
+
score, jid = params.split("-", 2)
|
156
215
|
[score.to_f, jid]
|
157
216
|
end
|
158
217
|
|
159
|
-
SAFE_QPARAMS = %w
|
218
|
+
SAFE_QPARAMS = %w[page direction]
|
160
219
|
|
161
220
|
# Merge options with current params, filter safe params, and stringify to query string
|
162
221
|
def qparams(options)
|
163
|
-
|
164
|
-
|
222
|
+
stringified_options = options.transform_keys(&:to_s)
|
223
|
+
|
224
|
+
to_query_string(params.merge(stringified_options))
|
225
|
+
end
|
226
|
+
|
227
|
+
def to_query_string(params)
|
228
|
+
params.map { |key, value|
|
165
229
|
SAFE_QPARAMS.include?(key) ? "#{key}=#{CGI.escape(value.to_s)}" : next
|
166
|
-
|
230
|
+
}.compact.join("&")
|
167
231
|
end
|
168
232
|
|
169
233
|
def truncate(text, truncate_after_chars = 2000)
|
@@ -171,33 +235,38 @@ module Sidekiq
|
|
171
235
|
end
|
172
236
|
|
173
237
|
def display_args(args, truncate_after_chars = 2000)
|
174
|
-
args
|
175
|
-
|
176
|
-
|
238
|
+
return "Invalid job payload, args is nil" if args.nil?
|
239
|
+
return "Invalid job payload, args must be an Array, not #{args.class.name}" unless args.is_a?(Array)
|
240
|
+
|
241
|
+
begin
|
242
|
+
args.map { |arg|
|
243
|
+
h(truncate(to_display(arg), truncate_after_chars))
|
244
|
+
}.join(", ")
|
245
|
+
rescue
|
246
|
+
"Illegal job arguments: #{h args.inspect}"
|
247
|
+
end
|
177
248
|
end
|
178
249
|
|
179
250
|
def csrf_tag
|
180
|
-
"<input type='hidden' name='authenticity_token' value='#{
|
251
|
+
"<input type='hidden' name='authenticity_token' value='#{env[:csrf_token]}'/>"
|
181
252
|
end
|
182
253
|
|
183
254
|
def to_display(arg)
|
255
|
+
arg.inspect
|
256
|
+
rescue
|
184
257
|
begin
|
185
|
-
arg.
|
186
|
-
rescue
|
187
|
-
|
188
|
-
arg.to_s
|
189
|
-
rescue => ex
|
190
|
-
"Cannot display argument: [#{ex.class.name}] #{ex.message}"
|
191
|
-
end
|
258
|
+
arg.to_s
|
259
|
+
rescue => ex
|
260
|
+
"Cannot display argument: [#{ex.class.name}] #{ex.message}"
|
192
261
|
end
|
193
262
|
end
|
194
263
|
|
195
|
-
RETRY_JOB_KEYS = Set.new(%w
|
264
|
+
RETRY_JOB_KEYS = Set.new(%w[
|
196
265
|
queue class args retry_count retried_at failed_at
|
197
266
|
jid error_message error_class backtrace
|
198
267
|
error_backtrace enqueued_at retry wrapped
|
199
|
-
created_at
|
200
|
-
)
|
268
|
+
created_at tags display_class
|
269
|
+
])
|
201
270
|
|
202
271
|
def retry_extra_items(retry_job)
|
203
272
|
@retry_extra_items ||= {}.tap do |extra|
|
@@ -207,15 +276,29 @@ module Sidekiq
|
|
207
276
|
end
|
208
277
|
end
|
209
278
|
|
279
|
+
def format_memory(rss_kb)
|
280
|
+
return "0" if rss_kb.nil? || rss_kb == 0
|
281
|
+
|
282
|
+
if rss_kb < 100_000
|
283
|
+
"#{number_with_delimiter(rss_kb)} KB"
|
284
|
+
elsif rss_kb < 10_000_000
|
285
|
+
"#{number_with_delimiter((rss_kb / 1024.0).to_i)} MB"
|
286
|
+
else
|
287
|
+
"#{number_with_delimiter((rss_kb / (1024.0 * 1024.0)).round(1))} GB"
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
210
291
|
def number_with_delimiter(number)
|
292
|
+
return "" if number.nil?
|
293
|
+
|
211
294
|
begin
|
212
295
|
Float(number)
|
213
296
|
rescue ArgumentError, TypeError
|
214
297
|
return number
|
215
298
|
end
|
216
299
|
|
217
|
-
options = {delimiter:
|
218
|
-
parts = number.to_s.to_str.split(
|
300
|
+
options = {delimiter: ",", separator: "."}
|
301
|
+
parts = number.to_s.to_str.split(".")
|
219
302
|
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
|
220
303
|
parts.join(options[:separator])
|
221
304
|
end
|
@@ -223,8 +306,8 @@ module Sidekiq
|
|
223
306
|
def h(text)
|
224
307
|
::Rack::Utils.escape_html(text)
|
225
308
|
rescue ArgumentError => e
|
226
|
-
raise unless e.message.eql?(
|
227
|
-
text.encode!(
|
309
|
+
raise unless e.message.eql?("invalid byte sequence in UTF-8")
|
310
|
+
text.encode!("UTF-16", "UTF-8", invalid: :replace, replace: "").encode!("UTF-8", "UTF-16")
|
228
311
|
retry
|
229
312
|
end
|
230
313
|
|
@@ -241,7 +324,7 @@ module Sidekiq
|
|
241
324
|
end
|
242
325
|
|
243
326
|
def environment_title_prefix
|
244
|
-
environment = Sidekiq
|
327
|
+
environment = Sidekiq[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
245
328
|
|
246
329
|
"[#{environment.upcase}] " unless environment == "production"
|
247
330
|
end
|
@@ -250,27 +333,31 @@ module Sidekiq
|
|
250
333
|
"Sidekiq v#{Sidekiq::VERSION}"
|
251
334
|
end
|
252
335
|
|
336
|
+
def server_utc_time
|
337
|
+
Time.now.utc.strftime("%H:%M:%S UTC")
|
338
|
+
end
|
339
|
+
|
253
340
|
def redis_connection_and_namespace
|
254
341
|
@redis_connection_and_namespace ||= begin
|
255
|
-
namespace_suffix = namespace
|
342
|
+
namespace_suffix = namespace.nil? ? "" : "##{namespace}"
|
256
343
|
"#{redis_connection}#{namespace_suffix}"
|
257
344
|
end
|
258
345
|
end
|
259
346
|
|
260
347
|
def retry_or_delete_or_kill(job, params)
|
261
|
-
if params[
|
348
|
+
if params["retry"]
|
262
349
|
job.retry
|
263
|
-
elsif params[
|
350
|
+
elsif params["delete"]
|
264
351
|
job.delete
|
265
|
-
elsif params[
|
352
|
+
elsif params["kill"]
|
266
353
|
job.kill
|
267
354
|
end
|
268
355
|
end
|
269
356
|
|
270
357
|
def delete_or_add_queue(job, params)
|
271
|
-
if params[
|
358
|
+
if params["delete"]
|
272
359
|
job.delete
|
273
|
-
elsif params[
|
360
|
+
elsif params["add_to_queue"]
|
274
361
|
job.add_to_queue
|
275
362
|
end
|
276
363
|
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)
|
@@ -35,10 +40,9 @@ module Sidekiq
|
|
35
40
|
end
|
36
41
|
|
37
42
|
def route(method, path, &block)
|
38
|
-
@routes ||= {
|
43
|
+
@routes ||= {GET => [], POST => [], PUT => [], PATCH => [], DELETE => [], HEAD => []}
|
39
44
|
|
40
45
|
@routes[method] << WebRoute.new(method, path, block)
|
41
|
-
@routes[HEAD] << WebRoute.new(method, path, block) if method == GET
|
42
46
|
end
|
43
47
|
|
44
48
|
def match(env)
|
@@ -50,7 +54,8 @@ module Sidekiq
|
|
50
54
|
path_info = "/" if path_info == ""
|
51
55
|
|
52
56
|
@routes[request_method].each do |route|
|
53
|
-
|
57
|
+
params = route.match(request_method, path_info)
|
58
|
+
if params
|
54
59
|
env[ROUTE_PARAMS] = params
|
55
60
|
|
56
61
|
return WebAction.new(env, route.block)
|
@@ -64,7 +69,7 @@ module Sidekiq
|
|
64
69
|
class WebRoute
|
65
70
|
attr_accessor :request_method, :pattern, :block, :name
|
66
71
|
|
67
|
-
NAMED_SEGMENTS_PATTERN = /\/([^\/]*):([
|
72
|
+
NAMED_SEGMENTS_PATTERN = /\/([^\/]*):([^.:$\/]+)/
|
68
73
|
|
69
74
|
def initialize(request_method, pattern, block)
|
70
75
|
@request_method = request_method
|
@@ -77,7 +82,7 @@ module Sidekiq
|
|
77
82
|
end
|
78
83
|
|
79
84
|
def compile
|
80
|
-
if pattern.match(NAMED_SEGMENTS_PATTERN)
|
85
|
+
if pattern.match?(NAMED_SEGMENTS_PATTERN)
|
81
86
|
p = pattern.gsub(NAMED_SEGMENTS_PATTERN, '/\1(?<\2>[^$/]+)')
|
82
87
|
|
83
88
|
Regexp.new("\\A#{p}\\Z")
|
@@ -91,9 +96,8 @@ module Sidekiq
|
|
91
96
|
when String
|
92
97
|
{} if path == matcher
|
93
98
|
else
|
94
|
-
|
95
|
-
|
96
|
-
end
|
99
|
+
path_match = path.match(matcher)
|
100
|
+
path_match&.named_captures&.transform_keys(&:to_sym)
|
97
101
|
end
|
98
102
|
end
|
99
103
|
end
|