sidekiq 6.5.12 → 7.0.6
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 +63 -22
- data/README.md +40 -32
- data/bin/sidekiq +3 -8
- data/bin/sidekiqload +186 -118
- data/bin/sidekiqmon +3 -0
- data/lib/sidekiq/api.rb +84 -121
- data/lib/sidekiq/capsule.rb +127 -0
- data/lib/sidekiq/cli.rb +55 -74
- data/lib/sidekiq/client.rb +29 -16
- data/lib/sidekiq/component.rb +3 -0
- data/lib/sidekiq/config.rb +270 -0
- data/lib/sidekiq/deploy.rb +62 -0
- data/lib/sidekiq/embedded.rb +61 -0
- data/lib/sidekiq/fetch.rb +11 -14
- data/lib/sidekiq/job.rb +375 -10
- data/lib/sidekiq/job_logger.rb +2 -2
- data/lib/sidekiq/job_retry.rb +9 -9
- data/lib/sidekiq/job_util.rb +48 -14
- data/lib/sidekiq/launcher.rb +64 -61
- data/lib/sidekiq/logger.rb +1 -26
- data/lib/sidekiq/manager.rb +9 -11
- data/lib/sidekiq/metrics/query.rb +2 -2
- data/lib/sidekiq/metrics/shared.rb +4 -3
- data/lib/sidekiq/metrics/tracking.rb +20 -18
- data/lib/sidekiq/middleware/chain.rb +19 -18
- data/lib/sidekiq/middleware/current_attributes.rb +8 -15
- data/lib/sidekiq/monitor.rb +16 -3
- data/lib/sidekiq/processor.rb +21 -27
- data/lib/sidekiq/rails.rb +13 -17
- data/lib/sidekiq/redis_client_adapter.rb +8 -47
- data/lib/sidekiq/redis_connection.rb +11 -111
- data/lib/sidekiq/scheduled.rb +20 -21
- data/lib/sidekiq/testing.rb +5 -33
- data/lib/sidekiq/transaction_aware_client.rb +4 -5
- data/lib/sidekiq/version.rb +2 -1
- data/lib/sidekiq/web/application.rb +21 -6
- data/lib/sidekiq/web/csrf_protection.rb +1 -1
- data/lib/sidekiq/web/helpers.rb +16 -15
- data/lib/sidekiq/web.rb +6 -17
- data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
- data/lib/sidekiq.rb +76 -274
- data/sidekiq.gemspec +20 -10
- data/web/assets/javascripts/application.js +18 -1
- data/web/assets/javascripts/base-charts.js +106 -0
- data/web/assets/javascripts/dashboard-charts.js +166 -0
- data/web/assets/javascripts/dashboard.js +3 -223
- data/web/assets/javascripts/metrics.js +117 -115
- data/web/assets/stylesheets/application-dark.css +4 -0
- data/web/assets/stylesheets/application-rtl.css +2 -91
- data/web/assets/stylesheets/application.css +23 -298
- data/web/locales/ar.yml +70 -70
- data/web/locales/cs.yml +62 -62
- data/web/locales/da.yml +60 -53
- data/web/locales/de.yml +65 -65
- data/web/locales/el.yml +2 -7
- data/web/locales/en.yml +76 -70
- data/web/locales/es.yml +68 -68
- data/web/locales/fa.yml +65 -65
- data/web/locales/fr.yml +67 -67
- data/web/locales/he.yml +65 -64
- data/web/locales/hi.yml +59 -59
- data/web/locales/it.yml +53 -53
- data/web/locales/ja.yml +64 -68
- data/web/locales/ko.yml +52 -52
- data/web/locales/lt.yml +66 -66
- 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 +59 -69
- data/web/locales/pt.yml +51 -51
- data/web/locales/ru.yml +67 -66
- data/web/locales/sv.yml +53 -53
- data/web/locales/ta.yml +60 -60
- data/web/locales/uk.yml +62 -61
- data/web/locales/ur.yml +64 -64
- data/web/locales/vi.yml +67 -67
- data/web/locales/zh-cn.yml +20 -18
- data/web/locales/zh-tw.yml +10 -1
- data/web/views/_footer.erb +5 -2
- data/web/views/_job_info.erb +18 -2
- data/web/views/_metrics_period_select.erb +12 -0
- data/web/views/_paging.erb +2 -0
- data/web/views/_poll_link.erb +1 -1
- data/web/views/busy.erb +37 -26
- data/web/views/dashboard.erb +36 -5
- data/web/views/metrics.erb +33 -20
- data/web/views/metrics_for_job.erb +22 -38
- data/web/views/morgue.erb +5 -9
- data/web/views/queue.erb +10 -14
- data/web/views/queues.erb +3 -1
- data/web/views/retries.erb +5 -9
- data/web/views/scheduled.erb +12 -13
- metadata +50 -40
- data/lib/sidekiq/delay.rb +0 -43
- data/lib/sidekiq/extensions/action_mailer.rb +0 -48
- data/lib/sidekiq/extensions/active_record.rb +0 -43
- data/lib/sidekiq/extensions/class_methods.rb +0 -43
- data/lib/sidekiq/extensions/generic_proxy.rb +0 -33
- data/lib/sidekiq/metrics/deploy.rb +0 -47
- data/lib/sidekiq/worker.rb +0 -370
- data/web/assets/javascripts/graph.js +0 -16
- /data/{LICENSE → LICENSE.txt} +0 -0
data/bin/sidekiqload
CHANGED
@@ -3,30 +3,43 @@
|
|
3
3
|
# Quiet some warnings we see when running in warning mode:
|
4
4
|
# RUBYOPT=-w bundle exec sidekiq
|
5
5
|
$TESTING = false
|
6
|
+
puts RUBY_DESCRIPTION
|
7
|
+
puts(%w[THREADS LATENCY AJ PROFILE].map { |x| "#{x}: #{ENV[x] || "nil"}" }.join(", "))
|
6
8
|
|
7
|
-
|
9
|
+
require "ruby-prof" if ENV["PROFILE"]
|
8
10
|
require "bundler/setup"
|
9
11
|
Bundler.require(:default, :load_test)
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
latency = Integer(ENV["LATENCY"] || 1)
|
14
|
+
if latency > 0
|
15
|
+
# brew tap shopify/shopify
|
16
|
+
# brew install toxiproxy
|
17
|
+
# run `toxiproxy-server` in a separate terminal window.
|
18
|
+
require "toxiproxy"
|
19
|
+
# simulate a non-localhost network for realer-world conditions.
|
20
|
+
# adding 1ms of network latency has an ENORMOUS impact on benchmarks
|
21
|
+
Toxiproxy.populate([{
|
22
|
+
name: "redis",
|
23
|
+
listen: "127.0.0.1:6380",
|
24
|
+
upstream: "127.0.0.1:6379"
|
25
|
+
}])
|
16
26
|
end
|
17
27
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
28
|
+
if ENV["AJ"]
|
29
|
+
require "active_job"
|
30
|
+
puts "Using ActiveJob #{ActiveJob::VERSION::STRING}"
|
31
|
+
ActiveJob::Base.queue_adapter = :sidekiq
|
32
|
+
ActiveJob::Base.logger.level = Logger::WARN
|
33
|
+
|
34
|
+
class LoadJob < ActiveJob::Base
|
35
|
+
def perform(idx, ts=nil)
|
36
|
+
puts(Time.now.to_f - ts) if !ts.nil?
|
37
|
+
end
|
38
|
+
end
|
26
39
|
end
|
27
40
|
|
28
41
|
class LoadWorker
|
29
|
-
include Sidekiq::
|
42
|
+
include Sidekiq::Job
|
30
43
|
sidekiq_options retry: 1
|
31
44
|
sidekiq_retry_in do |x|
|
32
45
|
1
|
@@ -38,124 +51,179 @@ class LoadWorker
|
|
38
51
|
end
|
39
52
|
end
|
40
53
|
|
41
|
-
|
42
|
-
|
43
|
-
# run `toxiproxy-server` in a separate terminal window.
|
44
|
-
require "toxiproxy"
|
45
|
-
# simulate a non-localhost network for realer-world conditions.
|
46
|
-
# adding 1ms of network latency has an ENORMOUS impact on benchmarks
|
47
|
-
Toxiproxy.populate([{
|
48
|
-
name: "redis",
|
49
|
-
listen: "127.0.0.1:6380",
|
50
|
-
upstream: "127.0.0.1:6379"
|
51
|
-
}])
|
52
|
-
|
53
|
-
self_read, self_write = IO.pipe
|
54
|
-
%w[INT TERM TSTP TTIN].each do |sig|
|
55
|
-
trap sig do
|
56
|
-
self_write.puts(sig)
|
57
|
-
end
|
58
|
-
rescue ArgumentError
|
59
|
-
puts "Signal #{sig} not supported"
|
54
|
+
def Process.rss
|
55
|
+
`ps -o rss= -p #{Process.pid}`.chomp.to_i
|
60
56
|
end
|
61
57
|
|
62
|
-
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
58
|
+
class Loader
|
59
|
+
def initialize
|
60
|
+
@iter = ENV["GC"] ? 10 : 500
|
61
|
+
@count = Integer(ENV["COUNT"] || 1_000)
|
62
|
+
@latency = Integer(ENV["LATENCY"] || 1)
|
63
|
+
end
|
64
|
+
|
65
|
+
def configure
|
66
|
+
@x = Sidekiq.configure_embed do |config|
|
67
|
+
config.redis = {db: 13, port: ((@latency > 0) ? 6380 : 6379)}
|
68
|
+
config.concurrency = Integer(ENV.fetch("THREADS", "10"))
|
69
|
+
# config.redis = { db: 13, port: 6380, driver: :hiredis}
|
70
|
+
config.queues = %w[default]
|
71
|
+
config.logger.level = Logger::WARN
|
72
|
+
config.average_scheduled_poll_interval = 2
|
73
|
+
config.reliable! if defined?(Sidekiq::Pro)
|
74
|
+
end
|
75
|
+
|
76
|
+
@self_read, @self_write = IO.pipe
|
77
|
+
%w[INT TERM TSTP TTIN].each do |sig|
|
78
|
+
trap sig do
|
79
|
+
@self_write.puts(sig)
|
83
80
|
end
|
81
|
+
rescue ArgumentError
|
82
|
+
puts "Signal #{sig} not supported"
|
84
83
|
end
|
85
84
|
end
|
86
|
-
end
|
87
85
|
|
88
|
-
def
|
89
|
-
|
90
|
-
|
86
|
+
def handle_signal(sig)
|
87
|
+
launcher = @x
|
88
|
+
Sidekiq.logger.debug "Got #{sig} signal"
|
89
|
+
case sig
|
90
|
+
when "INT"
|
91
|
+
# Handle Ctrl-C in JRuby like MRI
|
92
|
+
# http://jira.codehaus.org/browse/JRUBY-4637
|
93
|
+
raise Interrupt
|
94
|
+
when "TERM"
|
95
|
+
# Heroku sends TERM and then waits 30 seconds for process to exit.
|
96
|
+
raise Interrupt
|
97
|
+
when "TSTP"
|
98
|
+
Sidekiq.logger.info "Received TSTP, no longer accepting new work"
|
99
|
+
launcher.quiet
|
100
|
+
when "TTIN"
|
101
|
+
Thread.list.each do |thread|
|
102
|
+
Sidekiq.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread["label"]}"
|
103
|
+
if thread.backtrace
|
104
|
+
Sidekiq.logger.warn thread.backtrace.join("\n")
|
105
|
+
else
|
106
|
+
Sidekiq.logger.warn "<no backtrace available>"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
91
111
|
|
92
|
-
|
93
|
-
|
112
|
+
def setup
|
113
|
+
Sidekiq.logger.error("Setup RSS: #{Process.rss}")
|
114
|
+
Sidekiq.redis { |c| c.flushdb }
|
115
|
+
start = Time.now
|
116
|
+
if ENV["AJ"]
|
117
|
+
@iter.times do
|
118
|
+
@count.times do |idx|
|
119
|
+
LoadJob.perform_later(idx)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
else
|
123
|
+
@iter.times do
|
124
|
+
arr = Array.new(@count) { |idx| [idx] }
|
125
|
+
Sidekiq::Client.push_bulk("class" => LoadWorker, "args" => arr)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
Sidekiq.logger.warn "Created #{@count * @iter} jobs in #{Time.now - start} sec"
|
129
|
+
end
|
94
130
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
131
|
+
def monitor
|
132
|
+
@monitor = Thread.new do
|
133
|
+
GC.start
|
134
|
+
loop do
|
135
|
+
sleep 0.2
|
136
|
+
qsize = Sidekiq.redis do |conn|
|
137
|
+
conn.llen "queue:default"
|
138
|
+
end
|
139
|
+
total = qsize
|
140
|
+
if total == 0
|
141
|
+
ending = Time.now - @start
|
142
|
+
size = @iter * @count
|
143
|
+
Sidekiq.logger.error("Done, #{size} jobs in #{ending} sec, #{(size / ending).to_i} jobs/sec")
|
144
|
+
Sidekiq.logger.error("Ending RSS: #{Process.rss}")
|
145
|
+
Sidekiq.logger.error("Now here's the latency for three jobs")
|
146
|
+
|
147
|
+
if ENV["AJ"]
|
148
|
+
LoadJob.perform_later(1, Time.now.to_f)
|
149
|
+
LoadJob.perform_later(2, Time.now.to_f)
|
150
|
+
LoadJob.perform_later(3, Time.now.to_f)
|
151
|
+
else
|
152
|
+
LoadWorker.perform_async(1, Time.now.to_f)
|
153
|
+
LoadWorker.perform_async(2, Time.now.to_f)
|
154
|
+
LoadWorker.perform_async(3, Time.now.to_f)
|
155
|
+
end
|
156
|
+
|
157
|
+
sleep 0.1
|
158
|
+
@x.stop
|
159
|
+
Process.kill("INT", $$)
|
160
|
+
break
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
100
165
|
|
101
|
-
|
166
|
+
def with_latency(latency, &block)
|
167
|
+
Sidekiq.logger.error "Simulating #{latency}ms of latency between Sidekiq and redis"
|
168
|
+
if latency > 0
|
169
|
+
Toxiproxy[:redis].downstream(:latency, latency: latency).apply(&block)
|
170
|
+
else
|
171
|
+
yield
|
172
|
+
end
|
173
|
+
end
|
102
174
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
175
|
+
def run(name)
|
176
|
+
Sidekiq.logger.warn("Starting #{name}")
|
177
|
+
monitor
|
178
|
+
|
179
|
+
if ENV["PROFILE"]
|
180
|
+
RubyProf.exclude_threads = [@monitor]
|
181
|
+
RubyProf.start
|
182
|
+
elsif ENV["GC"]
|
183
|
+
GC.start
|
184
|
+
GC.compact
|
185
|
+
GC.disable
|
186
|
+
Sidekiq.logger.error("GC Start RSS: #{Process.rss}")
|
108
187
|
end
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
LoadWorker.perform_async(3, Time.now.to_f)
|
118
|
-
|
119
|
-
sleep 0.2
|
120
|
-
exit(0)
|
188
|
+
@start = Time.now
|
189
|
+
with_latency(@latency) do
|
190
|
+
@x.run
|
191
|
+
|
192
|
+
while (readable_io = IO.select([@self_read]))
|
193
|
+
signal = readable_io.first[0].gets.strip
|
194
|
+
handle_signal(signal)
|
195
|
+
end
|
121
196
|
end
|
197
|
+
# normal
|
198
|
+
rescue Interrupt
|
199
|
+
rescue => e
|
200
|
+
raise e if $DEBUG
|
201
|
+
warn e.message
|
202
|
+
warn e.backtrace.join("\n")
|
203
|
+
exit 1
|
204
|
+
ensure
|
205
|
+
@x.stop
|
122
206
|
end
|
123
|
-
end
|
124
207
|
|
125
|
-
def
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
208
|
+
def done
|
209
|
+
Sidekiq.logger.error("GC End RSS: #{Process.rss}") if ENV["GC"]
|
210
|
+
if ENV["PROFILE"]
|
211
|
+
Sidekiq.logger.error("Profiling...")
|
212
|
+
result = RubyProf.stop
|
213
|
+
printer = RubyProf::GraphHtmlPrinter.new(result)
|
214
|
+
printer.print(File.new("output.html", "w"), min_percent: 1)
|
215
|
+
end
|
131
216
|
end
|
132
217
|
end
|
133
218
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
with_latency(Integer(ENV.fetch("LATENCY", "1"))) do
|
142
|
-
launcher = Sidekiq::Launcher.new(Sidekiq)
|
143
|
-
launcher.run
|
144
|
-
|
145
|
-
while readable_io = IO.select([self_read])
|
146
|
-
signal = readable_io.first[0].gets.strip
|
147
|
-
handle_signal(launcher, signal)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
rescue SystemExit => e
|
151
|
-
# Sidekiq.logger.error("Profiling...")
|
152
|
-
# result = RubyProf.stop
|
153
|
-
# printer = RubyProf::GraphHtmlPrinter.new(result)
|
154
|
-
# printer.print(File.new("output.html", "w"), :min_percent => 1)
|
155
|
-
# normal
|
156
|
-
rescue => e
|
157
|
-
raise e if $DEBUG
|
158
|
-
warn e.message
|
159
|
-
warn e.backtrace.join("\n")
|
160
|
-
exit 1
|
219
|
+
ll = Loader.new
|
220
|
+
ll.configure
|
221
|
+
|
222
|
+
unless ENV["GC"] || ENV["PROFILE"]
|
223
|
+
ll.setup
|
224
|
+
ll.run("warmup")
|
161
225
|
end
|
226
|
+
|
227
|
+
ll.setup
|
228
|
+
ll.run("ideal")
|
229
|
+
ll.done
|