sidekiq 6.4.1 → 7.0.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 +172 -12
- data/README.md +41 -33
- data/bin/sidekiq +3 -8
- data/bin/sidekiqload +188 -114
- data/bin/sidekiqmon +3 -0
- data/lib/sidekiq/api.rb +275 -161
- data/lib/sidekiq/capsule.rb +127 -0
- data/lib/sidekiq/cli.rb +83 -88
- data/lib/sidekiq/client.rb +55 -43
- data/lib/sidekiq/component.rb +68 -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 +21 -22
- data/lib/sidekiq/job.rb +375 -10
- data/lib/sidekiq/job_logger.rb +2 -2
- data/lib/sidekiq/job_retry.rb +76 -54
- data/lib/sidekiq/job_util.rb +59 -19
- data/lib/sidekiq/launcher.rb +90 -82
- data/lib/sidekiq/logger.rb +6 -45
- data/lib/sidekiq/manager.rb +33 -32
- data/lib/sidekiq/metrics/query.rb +153 -0
- data/lib/sidekiq/metrics/shared.rb +95 -0
- data/lib/sidekiq/metrics/tracking.rb +136 -0
- data/lib/sidekiq/middleware/chain.rb +96 -51
- data/lib/sidekiq/middleware/current_attributes.rb +16 -17
- data/lib/sidekiq/middleware/i18n.rb +6 -4
- data/lib/sidekiq/middleware/modules.rb +21 -0
- data/lib/sidekiq/monitor.rb +17 -4
- data/lib/sidekiq/paginator.rb +11 -3
- data/lib/sidekiq/processor.rb +60 -60
- data/lib/sidekiq/rails.rb +12 -10
- data/lib/sidekiq/redis_client_adapter.rb +115 -0
- data/lib/sidekiq/redis_connection.rb +13 -82
- data/lib/sidekiq/ring_buffer.rb +29 -0
- data/lib/sidekiq/scheduled.rb +65 -37
- data/lib/sidekiq/testing/inline.rb +4 -4
- data/lib/sidekiq/testing.rb +41 -68
- data/lib/sidekiq/transaction_aware_client.rb +44 -0
- data/lib/sidekiq/version.rb +2 -1
- data/lib/sidekiq/web/action.rb +3 -3
- data/lib/sidekiq/web/application.rb +40 -9
- data/lib/sidekiq/web/csrf_protection.rb +3 -3
- data/lib/sidekiq/web/helpers.rb +34 -20
- data/lib/sidekiq/web.rb +7 -14
- data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
- data/lib/sidekiq.rb +84 -207
- data/sidekiq.gemspec +20 -10
- data/web/assets/javascripts/application.js +76 -26
- 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 +166 -0
- data/web/assets/javascripts/dashboard.js +3 -240
- data/web/assets/javascripts/metrics.js +264 -0
- data/web/assets/stylesheets/application-dark.css +4 -0
- data/web/assets/stylesheets/application-rtl.css +2 -91
- data/web/assets/stylesheets/application.css +66 -299
- 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 +43 -24
- data/web/locales/en.yml +82 -69
- 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 +73 -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 +63 -55
- 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 +43 -16
- data/web/locales/zh-tw.yml +42 -8
- 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/_nav.erb +1 -1
- data/web/views/_paging.erb +2 -0
- data/web/views/_poll_link.erb +1 -1
- data/web/views/_summary.erb +1 -1
- data/web/views/busy.erb +42 -26
- data/web/views/dashboard.erb +36 -4
- data/web/views/metrics.erb +82 -0
- data/web/views/metrics_for_job.erb +71 -0
- data/web/views/morgue.erb +5 -9
- data/web/views/queue.erb +15 -15
- data/web/views/queues.erb +3 -1
- data/web/views/retries.erb +5 -9
- data/web/views/scheduled.erb +12 -13
- metadata +63 -28
- data/lib/sidekiq/delay.rb +0 -43
- data/lib/sidekiq/exception_handler.rb +0 -27
- 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/util.rb +0 -108
- data/lib/sidekiq/worker.rb +0 -362
- /data/{LICENSE → LICENSE.txt} +0 -0
data/bin/sidekiqload
CHANGED
@@ -3,26 +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
|
-
|
16
|
-
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
+
}])
|
26
|
+
end
|
27
|
+
|
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
|
22
39
|
end
|
23
40
|
|
24
41
|
class LoadWorker
|
25
|
-
include Sidekiq::
|
42
|
+
include Sidekiq::Job
|
26
43
|
sidekiq_options retry: 1
|
27
44
|
sidekiq_retry_in do |x|
|
28
45
|
1
|
@@ -34,122 +51,179 @@ class LoadWorker
|
|
34
51
|
end
|
35
52
|
end
|
36
53
|
|
37
|
-
|
38
|
-
|
39
|
-
# gem install toxiproxy
|
40
|
-
# run `toxiproxy-server` in a separate terminal window.
|
41
|
-
require "toxiproxy"
|
42
|
-
# simulate a non-localhost network for realer-world conditions.
|
43
|
-
# adding 1ms of network latency has an ENORMOUS impact on benchmarks
|
44
|
-
Toxiproxy.populate([{
|
45
|
-
name: "redis",
|
46
|
-
listen: "127.0.0.1:6380",
|
47
|
-
upstream: "127.0.0.1:6379"
|
48
|
-
}])
|
49
|
-
|
50
|
-
self_read, self_write = IO.pipe
|
51
|
-
%w[INT TERM TSTP TTIN].each do |sig|
|
52
|
-
trap sig do
|
53
|
-
self_write.puts(sig)
|
54
|
-
end
|
55
|
-
rescue ArgumentError
|
56
|
-
puts "Signal #{sig} not supported"
|
54
|
+
def Process.rss
|
55
|
+
`ps -o rss= -p #{Process.pid}`.chomp.to_i
|
57
56
|
end
|
58
57
|
|
59
|
-
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
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)
|
80
80
|
end
|
81
|
+
rescue ArgumentError
|
82
|
+
puts "Signal #{sig} not supported"
|
81
83
|
end
|
82
84
|
end
|
83
|
-
end
|
84
85
|
|
85
|
-
def
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
94
|
-
|
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"
|
95
129
|
end
|
96
|
-
|
97
|
-
|
130
|
+
|
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
|
98
164
|
end
|
99
|
-
Sidekiq::Client.push_bulk("class" => LoadWorker, "args" => arr)
|
100
|
-
end
|
101
|
-
Sidekiq.logger.error "Created #{count * iter} jobs"
|
102
165
|
|
103
|
-
|
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
|
104
174
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
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}")
|
110
187
|
end
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
LoadWorker.perform_async(3, Time.now.to_f)
|
120
|
-
|
121
|
-
sleep 0.2
|
122
|
-
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
|
123
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
|
124
206
|
end
|
125
|
-
end
|
126
207
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
Sidekiq.logger.error "Simulating 1ms of latency between Sidekiq and redis"
|
135
|
-
Toxiproxy[:redis].downstream(:latency, latency: 1).apply do
|
136
|
-
launcher = Sidekiq::Launcher.new(Sidekiq.options)
|
137
|
-
launcher.run
|
138
|
-
|
139
|
-
while readable_io = IO.select([self_read])
|
140
|
-
signal = readable_io.first[0].gets.strip
|
141
|
-
handle_signal(launcher, signal)
|
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)
|
142
215
|
end
|
143
216
|
end
|
144
|
-
rescue SystemExit => e
|
145
|
-
# Sidekiq.logger.error("Profiling...")
|
146
|
-
# result = RubyProf.stop
|
147
|
-
# printer = RubyProf::GraphHtmlPrinter.new(result)
|
148
|
-
# printer.print(File.new("output.html", "w"), :min_percent => 1)
|
149
|
-
# normal
|
150
|
-
rescue => e
|
151
|
-
raise e if $DEBUG
|
152
|
-
warn e.message
|
153
|
-
warn e.backtrace.join("\n")
|
154
|
-
exit 1
|
155
217
|
end
|
218
|
+
|
219
|
+
ll = Loader.new
|
220
|
+
ll.configure
|
221
|
+
|
222
|
+
unless ENV["GC"] || ENV["PROFILE"]
|
223
|
+
ll.setup
|
224
|
+
ll.run("warmup")
|
225
|
+
end
|
226
|
+
|
227
|
+
ll.setup
|
228
|
+
ll.run("ideal")
|
229
|
+
ll.done
|