sidekiq 6.1.1 → 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 +4 -4
- data/Changes.md +230 -3
- data/LICENSE +3 -3
- data/README.md +10 -6
- data/bin/sidekiq +3 -3
- data/bin/sidekiqload +70 -66
- data/bin/sidekiqmon +1 -1
- 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/{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 +335 -146
- data/lib/sidekiq/cli.rb +74 -41
- data/lib/sidekiq/client.rb +48 -72
- data/lib/sidekiq/{util.rb → component.rb} +12 -14
- data/lib/sidekiq/delay.rb +3 -1
- data/lib/sidekiq/extensions/action_mailer.rb +3 -2
- data/lib/sidekiq/extensions/active_record.rb +1 -1
- data/lib/sidekiq/extensions/generic_proxy.rb +4 -2
- data/lib/sidekiq/fetch.rb +31 -20
- data/lib/sidekiq/job.rb +13 -0
- data/lib/sidekiq/job_logger.rb +16 -28
- data/lib/sidekiq/job_retry.rb +79 -59
- data/lib/sidekiq/job_util.rb +71 -0
- data/lib/sidekiq/launcher.rb +126 -65
- data/lib/sidekiq/logger.rb +11 -20
- data/lib/sidekiq/manager.rb +35 -34
- 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 +88 -42
- data/lib/sidekiq/middleware/current_attributes.rb +63 -0
- data/lib/sidekiq/middleware/i18n.rb +6 -4
- data/lib/sidekiq/middleware/modules.rb +21 -0
- data/lib/sidekiq/monitor.rb +1 -1
- data/lib/sidekiq/paginator.rb +8 -8
- data/lib/sidekiq/processor.rb +47 -41
- data/lib/sidekiq/rails.rb +22 -4
- data/lib/sidekiq/redis_client_adapter.rb +154 -0
- data/lib/sidekiq/redis_connection.rb +84 -55
- data/lib/sidekiq/ring_buffer.rb +29 -0
- data/lib/sidekiq/scheduled.rb +96 -32
- data/lib/sidekiq/testing/inline.rb +4 -4
- data/lib/sidekiq/testing.rb +38 -39
- data/lib/sidekiq/transaction_aware_client.rb +45 -0
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/action.rb +3 -3
- data/lib/sidekiq/web/application.rb +38 -16
- data/lib/sidekiq/web/csrf_protection.rb +32 -5
- data/lib/sidekiq/web/helpers.rb +60 -28
- data/lib/sidekiq/web/router.rb +4 -1
- data/lib/sidekiq/web.rb +38 -78
- data/lib/sidekiq/worker.rb +140 -14
- data/lib/sidekiq.rb +114 -31
- data/sidekiq.gemspec +12 -4
- data/web/assets/images/apple-touch-icon.png +0 -0
- data/web/assets/javascripts/application.js +113 -60
- 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 +50 -67
- data/web/assets/javascripts/graph.js +16 -0
- data/web/assets/javascripts/metrics.js +262 -0
- data/web/assets/stylesheets/application-dark.css +61 -51
- data/web/assets/stylesheets/application-rtl.css +0 -4
- data/web/assets/stylesheets/application.css +84 -243
- data/web/locales/ar.yml +8 -2
- data/web/locales/el.yml +43 -19
- data/web/locales/en.yml +11 -1
- data/web/locales/es.yml +18 -2
- data/web/locales/fr.yml +8 -1
- data/web/locales/ja.yml +10 -0
- data/web/locales/lt.yml +1 -1
- data/web/locales/pt-br.yml +27 -9
- data/web/locales/ru.yml +4 -0
- data/web/locales/zh-cn.yml +36 -11
- data/web/locales/zh-tw.yml +32 -7
- data/web/views/_footer.erb +1 -1
- data/web/views/_job_info.erb +1 -1
- data/web/views/_nav.erb +1 -1
- data/web/views/_poll_link.erb +2 -5
- data/web/views/_summary.erb +7 -7
- data/web/views/busy.erb +52 -21
- data/web/views/dashboard.erb +23 -14
- data/web/views/dead.erb +1 -1
- data/web/views/layout.erb +2 -1
- data/web/views/metrics.erb +69 -0
- data/web/views/metrics_for_job.erb +87 -0
- data/web/views/morgue.erb +6 -6
- data/web/views/queue.erb +15 -11
- data/web/views/queues.erb +4 -4
- data/web/views/retries.erb +7 -7
- data/web/views/retry.erb +1 -1
- data/web/views/scheduled.erb +1 -1
- metadata +46 -39
- data/.circleci/config.yml +0 -71
- data/.github/contributing.md +0 -32
- data/.github/issue_template.md +0 -11
- data/.gitignore +0 -13
- data/.standard.yml +0 -20
- data/3.0-Upgrade.md +0 -70
- data/4.0-Upgrade.md +0 -53
- data/5.0-Upgrade.md +0 -56
- data/6.0-Upgrade.md +0 -72
- data/COMM-LICENSE +0 -97
- data/Ent-2.0-Upgrade.md +0 -37
- data/Ent-Changes.md +0 -275
- data/Gemfile +0 -24
- data/Gemfile.lock +0 -208
- 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-5.0-Upgrade.md +0 -25
- data/Pro-Changes.md +0 -795
- data/Rakefile +0 -10
- data/code_of_conduct.md +0 -50
- data/lib/generators/sidekiq/worker_generator.rb +0 -57
- data/lib/sidekiq/exception_handler.rb +0 -27
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "securerandom"
|
4
|
+
require "sidekiq/client"
|
5
|
+
|
6
|
+
module Sidekiq
|
7
|
+
class TransactionAwareClient
|
8
|
+
def initialize(redis_pool)
|
9
|
+
@redis_client = Client.new(redis_pool)
|
10
|
+
end
|
11
|
+
|
12
|
+
def push(item)
|
13
|
+
# pre-allocate the JID so we can return it immediately and
|
14
|
+
# save it to the database as part of the transaction.
|
15
|
+
item["jid"] ||= SecureRandom.hex(12)
|
16
|
+
AfterCommitEverywhere.after_commit { @redis_client.push(item) }
|
17
|
+
item["jid"]
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# We don't provide transactionality for push_bulk because we don't want
|
22
|
+
# to hold potentially hundreds of thousands of job records in memory due to
|
23
|
+
# a long running enqueue process.
|
24
|
+
def push_bulk(items)
|
25
|
+
@redis_client.push_bulk(items)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Use `Sidekiq.transactional_push!` in your sidekiq.rb initializer
|
32
|
+
module Sidekiq
|
33
|
+
def self.transactional_push!
|
34
|
+
begin
|
35
|
+
require "after_commit_everywhere"
|
36
|
+
rescue LoadError
|
37
|
+
Sidekiq.logger.error("You need to add after_commit_everywhere to your Gemfile to use Sidekiq's transactional client")
|
38
|
+
raise
|
39
|
+
end
|
40
|
+
|
41
|
+
default_job_options["client_class"] = Sidekiq::TransactionAwareClient
|
42
|
+
Sidekiq::JobUtil::TRANSIENT_ATTRIBUTES << "client_class"
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/web/action.rb
CHANGED
@@ -15,11 +15,11 @@ module Sidekiq
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def halt(res)
|
18
|
-
throw :halt, res
|
18
|
+
throw :halt, [res, {"content-type" => "text/plain"}, [res.to_s]]
|
19
19
|
end
|
20
20
|
|
21
21
|
def redirect(location)
|
22
|
-
throw :halt, [302, {"
|
22
|
+
throw :halt, [302, {"location" => "#{request.base_url}#{location}"}, []]
|
23
23
|
end
|
24
24
|
|
25
25
|
def params
|
@@ -68,7 +68,7 @@ module Sidekiq
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def json(payload)
|
71
|
-
[200, {"
|
71
|
+
[200, {"content-type" => "application/json", "cache-control" => "private, no-store"}, [Sidekiq.dump_json(payload)]]
|
72
72
|
end
|
73
73
|
|
74
74
|
def initialize(env, block)
|
@@ -4,7 +4,6 @@ module Sidekiq
|
|
4
4
|
class WebApplication
|
5
5
|
extend WebRouter
|
6
6
|
|
7
|
-
CONTENT_LENGTH = "Content-Length"
|
8
7
|
REDIS_KEYS = %w[redis_version uptime_in_days connected_clients used_memory_human used_memory_peak_human]
|
9
8
|
CSP_HEADER = [
|
10
9
|
"default-src 'self' https: http:",
|
@@ -42,15 +41,38 @@ module Sidekiq
|
|
42
41
|
# nothing, backwards compatibility
|
43
42
|
end
|
44
43
|
|
44
|
+
head "/" do
|
45
|
+
# HEAD / is the cheapest heartbeat possible,
|
46
|
+
# it hits Redis to ensure connectivity
|
47
|
+
Sidekiq.redis { |c| c.llen("queue:default") }
|
48
|
+
""
|
49
|
+
end
|
50
|
+
|
45
51
|
get "/" do
|
46
52
|
@redis_info = redis_info.select { |k, v| REDIS_KEYS.include? k }
|
47
|
-
|
53
|
+
days = (params["days"] || 30).to_i
|
54
|
+
return halt(401) if days < 1 || days > 180
|
55
|
+
|
56
|
+
stats_history = Sidekiq::Stats::History.new(days)
|
48
57
|
@processed_history = stats_history.processed
|
49
58
|
@failed_history = stats_history.failed
|
50
59
|
|
51
60
|
erb(:dashboard)
|
52
61
|
end
|
53
62
|
|
63
|
+
get "/metrics" do
|
64
|
+
q = Sidekiq::Metrics::Query.new
|
65
|
+
@query_result = q.top_jobs
|
66
|
+
erb(:metrics)
|
67
|
+
end
|
68
|
+
|
69
|
+
get "/metrics/:name" do
|
70
|
+
@name = route_params[:name]
|
71
|
+
q = Sidekiq::Metrics::Query.new
|
72
|
+
@query_result = q.for_job(@name)
|
73
|
+
erb(:metrics_for_job)
|
74
|
+
end
|
75
|
+
|
54
76
|
get "/busy" do
|
55
77
|
erb(:busy)
|
56
78
|
end
|
@@ -76,15 +98,17 @@ module Sidekiq
|
|
76
98
|
erb(:queues)
|
77
99
|
end
|
78
100
|
|
101
|
+
QUEUE_NAME = /\A[a-z_:.\-0-9]+\z/i
|
102
|
+
|
79
103
|
get "/queues/:name" do
|
80
104
|
@name = route_params[:name]
|
81
105
|
|
82
|
-
halt(404)
|
106
|
+
halt(404) if !@name || @name !~ QUEUE_NAME
|
83
107
|
|
84
108
|
@count = (params["count"] || 25).to_i
|
85
109
|
@queue = Sidekiq::Queue.new(@name)
|
86
|
-
(@current_page, @total_size, @
|
87
|
-
@
|
110
|
+
(@current_page, @total_size, @jobs) = page("queue:#{@name}", params["page"], @count, reverse: params["direction"] == "asc")
|
111
|
+
@jobs = @jobs.map { |msg| Sidekiq::JobRecord.new(msg, @name) }
|
88
112
|
|
89
113
|
erb(:queue)
|
90
114
|
end
|
@@ -105,7 +129,7 @@ module Sidekiq
|
|
105
129
|
|
106
130
|
post "/queues/:name/delete" do
|
107
131
|
name = route_params[:name]
|
108
|
-
Sidekiq::
|
132
|
+
Sidekiq::JobRecord.new(params["key_val"], name).delete
|
109
133
|
|
110
134
|
redirect_with_query("#{root_path}queues/#{CGI.escape(name)}")
|
111
135
|
end
|
@@ -288,37 +312,35 @@ module Sidekiq
|
|
288
312
|
|
289
313
|
def call(env)
|
290
314
|
action = self.class.match(env)
|
291
|
-
return [404, {"
|
315
|
+
return [404, {"content-type" => "text/plain", "x-cascade" => "pass"}, ["Not Found"]] unless action
|
292
316
|
|
293
317
|
app = @klass
|
294
|
-
resp = catch(:halt) do
|
318
|
+
resp = catch(:halt) do
|
295
319
|
self.class.run_befores(app, action)
|
296
320
|
action.instance_exec env, &action.block
|
297
321
|
ensure
|
298
322
|
self.class.run_afters(app, action)
|
299
323
|
end
|
300
324
|
|
301
|
-
|
325
|
+
case resp
|
302
326
|
when Array
|
303
327
|
# redirects go here
|
304
328
|
resp
|
305
329
|
else
|
306
330
|
# rendered content goes here
|
307
331
|
headers = {
|
308
|
-
"
|
309
|
-
"
|
310
|
-
"
|
311
|
-
"
|
332
|
+
"content-type" => "text/html",
|
333
|
+
"cache-control" => "private, no-store",
|
334
|
+
"content-language" => action.locale,
|
335
|
+
"content-security-policy" => CSP_HEADER
|
312
336
|
}
|
313
337
|
# we'll let Rack calculate Content-Length for us.
|
314
338
|
[200, headers, [resp]]
|
315
339
|
end
|
316
|
-
|
317
|
-
resp
|
318
340
|
end
|
319
341
|
|
320
342
|
def self.helpers(mod = nil, &block)
|
321
|
-
if
|
343
|
+
if block
|
322
344
|
WebAction.class_eval(&block)
|
323
345
|
else
|
324
346
|
WebAction.send(:include, mod)
|
@@ -66,13 +66,37 @@ module Sidekiq
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def session(env)
|
69
|
-
env["rack.session"] || fail(
|
69
|
+
env["rack.session"] || fail(<<~EOM)
|
70
|
+
Sidekiq::Web needs a valid Rack session for CSRF protection. If this is a Rails app,
|
71
|
+
make sure you mount Sidekiq::Web *inside* your application routes:
|
72
|
+
|
73
|
+
|
74
|
+
Rails.application.routes.draw do
|
75
|
+
mount Sidekiq::Web => "/sidekiq"
|
76
|
+
....
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
If this is a Rails app in API mode, you need to enable sessions.
|
81
|
+
|
82
|
+
https://guides.rubyonrails.org/api_app.html#using-session-middlewares
|
83
|
+
|
84
|
+
If this is a bare Rack app, use a session middleware before Sidekiq::Web:
|
85
|
+
|
86
|
+
# first, use IRB to create a shared secret key for sessions and commit it
|
87
|
+
require 'securerandom'; File.open(".session.key", "w") {|f| f.write(SecureRandom.hex(32)) }
|
88
|
+
|
89
|
+
# now use the secret with a session cookie middleware
|
90
|
+
use Rack::Session::Cookie, secret: File.read(".session.key"), same_site: true, max_age: 86400
|
91
|
+
run Sidekiq::Web
|
92
|
+
|
93
|
+
EOM
|
70
94
|
end
|
71
95
|
|
72
96
|
def accept?(env)
|
73
97
|
return true if safe?(env)
|
74
98
|
|
75
|
-
giventoken = Rack::Request.new(env).params["authenticity_token"]
|
99
|
+
giventoken = ::Rack::Request.new(env).params["authenticity_token"]
|
76
100
|
valid_token?(env, giventoken)
|
77
101
|
end
|
78
102
|
|
@@ -92,6 +116,9 @@ module Sidekiq
|
|
92
116
|
sess = session(env)
|
93
117
|
localtoken = sess[:csrf]
|
94
118
|
|
119
|
+
# Checks that Rack::Session::Cookie actualy contains the csrf toekn
|
120
|
+
return false if localtoken.nil?
|
121
|
+
|
95
122
|
# Rotate the session token after every use
|
96
123
|
sess[:csrf] = SecureRandom.base64(TOKEN_LENGTH)
|
97
124
|
|
@@ -116,7 +143,7 @@ module Sidekiq
|
|
116
143
|
one_time_pad = SecureRandom.random_bytes(token.length)
|
117
144
|
encrypted_token = xor_byte_strings(one_time_pad, token)
|
118
145
|
masked_token = one_time_pad + encrypted_token
|
119
|
-
Base64.
|
146
|
+
Base64.urlsafe_encode64(masked_token)
|
120
147
|
end
|
121
148
|
|
122
149
|
# Essentially the inverse of +mask_token+.
|
@@ -138,11 +165,11 @@ module Sidekiq
|
|
138
165
|
end
|
139
166
|
|
140
167
|
def compare_with_real_token(token, local)
|
141
|
-
Rack::Utils.secure_compare(token.to_s, decode_token(local).to_s)
|
168
|
+
::Rack::Utils.secure_compare(token.to_s, decode_token(local).to_s)
|
142
169
|
end
|
143
170
|
|
144
171
|
def decode_token(token)
|
145
|
-
Base64.
|
172
|
+
Base64.urlsafe_decode64(token)
|
146
173
|
end
|
147
174
|
|
148
175
|
def xor_byte_strings(s1, s2)
|
data/lib/sidekiq/web/helpers.rb
CHANGED
@@ -10,18 +10,25 @@ module Sidekiq
|
|
10
10
|
module WebHelpers
|
11
11
|
def strings(lang)
|
12
12
|
@strings ||= {}
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
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])
|
21
20
|
end
|
22
21
|
end
|
23
22
|
end
|
24
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
|
+
|
25
32
|
def clear_caches
|
26
33
|
@strings = nil
|
27
34
|
@locale_files = nil
|
@@ -63,17 +70,6 @@ module Sidekiq
|
|
63
70
|
@head_html.join if defined?(@head_html)
|
64
71
|
end
|
65
72
|
|
66
|
-
def poll_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
|
72
|
-
else
|
73
|
-
""
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
73
|
def text_direction
|
78
74
|
get_locale["TextDirection"] || "ltr"
|
79
75
|
end
|
@@ -118,7 +114,7 @@ module Sidekiq
|
|
118
114
|
# within is used by Sidekiq Pro
|
119
115
|
def display_tags(job, within = nil)
|
120
116
|
job.tags.map { |tag|
|
121
|
-
"<span class='
|
117
|
+
"<span class='label label-info jobtag'>#{::Rack::Utils.escape_html(tag)}</span>"
|
122
118
|
}.join(" ")
|
123
119
|
end
|
124
120
|
|
@@ -144,22 +140,44 @@ module Sidekiq
|
|
144
140
|
params[:direction] == "asc" ? "↑" : "↓"
|
145
141
|
end
|
146
142
|
|
147
|
-
def
|
148
|
-
@
|
143
|
+
def workset
|
144
|
+
@work ||= Sidekiq::WorkSet.new
|
149
145
|
end
|
150
146
|
|
151
147
|
def processes
|
152
148
|
@processes ||= Sidekiq::ProcessSet.new
|
153
149
|
end
|
154
150
|
|
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
|
172
|
+
end
|
173
|
+
|
155
174
|
def stats
|
156
175
|
@stats ||= Sidekiq::Stats.new
|
157
176
|
end
|
158
177
|
|
159
178
|
def redis_connection
|
160
179
|
Sidekiq.redis do |conn|
|
161
|
-
|
162
|
-
"redis://#{c[:location]}/#{c[:db]}"
|
180
|
+
conn.connection[:id]
|
163
181
|
end
|
164
182
|
end
|
165
183
|
|
@@ -180,7 +198,7 @@ module Sidekiq
|
|
180
198
|
end
|
181
199
|
|
182
200
|
def current_status
|
183
|
-
|
201
|
+
workset.size == 0 ? "idle" : "active"
|
184
202
|
end
|
185
203
|
|
186
204
|
def relative_time(time)
|
@@ -197,7 +215,7 @@ module Sidekiq
|
|
197
215
|
[score.to_f, jid]
|
198
216
|
end
|
199
217
|
|
200
|
-
SAFE_QPARAMS = %w[page
|
218
|
+
SAFE_QPARAMS = %w[page direction]
|
201
219
|
|
202
220
|
# Merge options with current params, filter safe params, and stringify to query string
|
203
221
|
def qparams(options)
|
@@ -247,7 +265,7 @@ module Sidekiq
|
|
247
265
|
queue class args retry_count retried_at failed_at
|
248
266
|
jid error_message error_class backtrace
|
249
267
|
error_backtrace enqueued_at retry wrapped
|
250
|
-
created_at tags
|
268
|
+
created_at tags display_class
|
251
269
|
])
|
252
270
|
|
253
271
|
def retry_extra_items(retry_job)
|
@@ -258,7 +276,21 @@ module Sidekiq
|
|
258
276
|
end
|
259
277
|
end
|
260
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
|
+
|
261
291
|
def number_with_delimiter(number)
|
292
|
+
return "" if number.nil?
|
293
|
+
|
262
294
|
begin
|
263
295
|
Float(number)
|
264
296
|
rescue ArgumentError, TypeError
|
@@ -292,7 +324,7 @@ module Sidekiq
|
|
292
324
|
end
|
293
325
|
|
294
326
|
def environment_title_prefix
|
295
|
-
environment = Sidekiq
|
327
|
+
environment = Sidekiq[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
296
328
|
|
297
329
|
"[#{environment.upcase}] " unless environment == "production"
|
298
330
|
end
|
data/lib/sidekiq/web/router.rb
CHANGED
@@ -15,6 +15,10 @@ module Sidekiq
|
|
15
15
|
REQUEST_METHOD = "REQUEST_METHOD"
|
16
16
|
PATH_INFO = "PATH_INFO"
|
17
17
|
|
18
|
+
def head(path, &block)
|
19
|
+
route(HEAD, path, &block)
|
20
|
+
end
|
21
|
+
|
18
22
|
def get(path, &block)
|
19
23
|
route(GET, path, &block)
|
20
24
|
end
|
@@ -39,7 +43,6 @@ module Sidekiq
|
|
39
43
|
@routes ||= {GET => [], POST => [], PUT => [], PATCH => [], DELETE => [], HEAD => []}
|
40
44
|
|
41
45
|
@routes[method] << WebRoute.new(method, path, block)
|
42
|
-
@routes[HEAD] << WebRoute.new(method, path, block) if method == GET
|
43
46
|
end
|
44
47
|
|
45
48
|
def match(env)
|
data/lib/sidekiq/web.rb
CHANGED
@@ -13,10 +13,8 @@ require "sidekiq/web/application"
|
|
13
13
|
require "sidekiq/web/csrf_protection"
|
14
14
|
|
15
15
|
require "rack/content_length"
|
16
|
-
|
17
16
|
require "rack/builder"
|
18
|
-
require "rack/
|
19
|
-
require "rack/session/cookie"
|
17
|
+
require "rack/static"
|
20
18
|
|
21
19
|
module Sidekiq
|
22
20
|
class Web
|
@@ -35,19 +33,15 @@ module Sidekiq
|
|
35
33
|
"Dead" => "morgue"
|
36
34
|
}
|
37
35
|
|
36
|
+
if ENV["SIDEKIQ_METRICS_BETA"] == "1"
|
37
|
+
DEFAULT_TABS["Metrics"] = "metrics"
|
38
|
+
end
|
39
|
+
|
38
40
|
class << self
|
39
41
|
def settings
|
40
42
|
self
|
41
43
|
end
|
42
44
|
|
43
|
-
def middlewares
|
44
|
-
@middlewares ||= []
|
45
|
-
end
|
46
|
-
|
47
|
-
def use(*middleware_args, &block)
|
48
|
-
middlewares << [middleware_args, block]
|
49
|
-
end
|
50
|
-
|
51
45
|
def default_tabs
|
52
46
|
DEFAULT_TABS
|
53
47
|
end
|
@@ -73,32 +67,45 @@ module Sidekiq
|
|
73
67
|
opts.each { |key| set(key, false) }
|
74
68
|
end
|
75
69
|
|
76
|
-
|
70
|
+
def middlewares
|
71
|
+
@middlewares ||= []
|
72
|
+
end
|
73
|
+
|
74
|
+
def use(*args, &block)
|
75
|
+
middlewares << [args, block]
|
76
|
+
end
|
77
|
+
|
77
78
|
def set(attribute, value)
|
78
79
|
send(:"#{attribute}=", value)
|
79
80
|
end
|
80
81
|
|
81
|
-
|
82
|
+
def sessions=(val)
|
83
|
+
puts "WARNING: Sidekiq::Web.sessions= is no longer relevant and will be removed in Sidekiq 7.0. #{caller(1..1).first}"
|
84
|
+
end
|
85
|
+
|
86
|
+
def session_secret=(val)
|
87
|
+
puts "WARNING: Sidekiq::Web.session_secret= is no longer relevant and will be removed in Sidekiq 7.0. #{caller(1..1).first}"
|
88
|
+
end
|
89
|
+
|
90
|
+
attr_accessor :app_url, :redis_pool
|
82
91
|
attr_writer :locales, :views
|
83
92
|
end
|
84
93
|
|
85
94
|
def self.inherited(child)
|
86
95
|
child.app_url = app_url
|
87
|
-
child.session_secret = session_secret
|
88
96
|
child.redis_pool = redis_pool
|
89
|
-
child.sessions = sessions
|
90
97
|
end
|
91
98
|
|
92
99
|
def settings
|
93
100
|
self.class.settings
|
94
101
|
end
|
95
102
|
|
96
|
-
def
|
97
|
-
middlewares
|
103
|
+
def middlewares
|
104
|
+
@middlewares ||= self.class.middlewares
|
98
105
|
end
|
99
106
|
|
100
|
-
def
|
101
|
-
|
107
|
+
def use(*args, &block)
|
108
|
+
middlewares << [args, block]
|
102
109
|
end
|
103
110
|
|
104
111
|
def call(env)
|
@@ -126,18 +133,8 @@ module Sidekiq
|
|
126
133
|
send(:"#{attribute}=", value)
|
127
134
|
end
|
128
135
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
attr_writer :sessions
|
133
|
-
|
134
|
-
def sessions
|
135
|
-
unless instance_variable_defined?("@sessions")
|
136
|
-
@sessions = self.class.sessions
|
137
|
-
@sessions = @sessions.to_hash.dup if @sessions.respond_to?(:to_hash)
|
138
|
-
end
|
139
|
-
|
140
|
-
@sessions
|
136
|
+
def sessions=(val)
|
137
|
+
puts "Sidekiq::Web#sessions= is no longer relevant and will be removed in Sidekiq 7.0. #{caller[2..2].first}"
|
141
138
|
end
|
142
139
|
|
143
140
|
def self.register(extension)
|
@@ -146,57 +143,20 @@ module Sidekiq
|
|
146
143
|
|
147
144
|
private
|
148
145
|
|
149
|
-
def using?(middleware)
|
150
|
-
middlewares.any? do |(m, _)|
|
151
|
-
m.is_a?(Array) && (m[0] == middleware || m[0].is_a?(middleware))
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
def build_sessions
|
156
|
-
middlewares = self.middlewares
|
157
|
-
|
158
|
-
s = sessions
|
159
|
-
|
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"
|
168
|
-
secret = SecureRandom.hex(64)
|
169
|
-
end
|
170
|
-
|
171
|
-
options = {secret: secret}
|
172
|
-
options = options.merge(s.to_hash) if s.respond_to? :to_hash
|
173
|
-
|
174
|
-
middlewares.unshift [[::Rack::Session::Cookie, options], nil]
|
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
|
183
|
-
end
|
184
|
-
|
185
146
|
def build
|
186
|
-
build_sessions
|
187
|
-
|
188
|
-
middlewares = self.middlewares
|
189
147
|
klass = self.class
|
148
|
+
m = middlewares
|
190
149
|
|
191
|
-
|
192
|
-
|
193
|
-
map "/#{asset_dir}" do
|
194
|
-
run ::Rack::File.new("#{ASSETS}/#{asset_dir}", {"Cache-Control" => "public, max-age=86400"})
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
middlewares.each { |middleware, block| use(*middleware, &block) }
|
150
|
+
rules = []
|
151
|
+
rules = [[:all, {"cache-control" => "public, max-age=86400"}]] unless ENV["SIDEKIQ_WEB_TESTING"]
|
199
152
|
|
153
|
+
::Rack::Builder.new do
|
154
|
+
use Rack::Static, urls: ["/stylesheets", "/images", "/javascripts"],
|
155
|
+
root: ASSETS,
|
156
|
+
cascade: true,
|
157
|
+
header_rules: rules
|
158
|
+
m.each { |middleware, block| use(*middleware, &block) }
|
159
|
+
use Sidekiq::Web::CsrfProtection unless $TESTING
|
200
160
|
run WebApplication.new(klass)
|
201
161
|
end
|
202
162
|
end
|