sidekiq 6.5.9 → 7.0.9

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.

Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +93 -17
  3. data/README.md +40 -32
  4. data/bin/sidekiq +3 -8
  5. data/bin/sidekiqload +186 -118
  6. data/bin/sidekiqmon +3 -0
  7. data/lib/sidekiq/api.rb +84 -121
  8. data/lib/sidekiq/capsule.rb +127 -0
  9. data/lib/sidekiq/cli.rb +55 -74
  10. data/lib/sidekiq/client.rb +29 -16
  11. data/lib/sidekiq/component.rb +3 -0
  12. data/lib/sidekiq/config.rb +270 -0
  13. data/lib/sidekiq/deploy.rb +62 -0
  14. data/lib/sidekiq/embedded.rb +61 -0
  15. data/lib/sidekiq/fetch.rb +11 -14
  16. data/lib/sidekiq/job.rb +375 -10
  17. data/lib/sidekiq/job_logger.rb +2 -2
  18. data/lib/sidekiq/job_retry.rb +13 -12
  19. data/lib/sidekiq/job_util.rb +48 -14
  20. data/lib/sidekiq/launcher.rb +65 -61
  21. data/lib/sidekiq/logger.rb +1 -26
  22. data/lib/sidekiq/manager.rb +9 -11
  23. data/lib/sidekiq/metrics/query.rb +3 -3
  24. data/lib/sidekiq/metrics/shared.rb +7 -6
  25. data/lib/sidekiq/metrics/tracking.rb +20 -18
  26. data/lib/sidekiq/middleware/chain.rb +19 -18
  27. data/lib/sidekiq/middleware/current_attributes.rb +8 -15
  28. data/lib/sidekiq/monitor.rb +16 -3
  29. data/lib/sidekiq/processor.rb +21 -27
  30. data/lib/sidekiq/rails.rb +4 -9
  31. data/lib/sidekiq/redis_client_adapter.rb +8 -47
  32. data/lib/sidekiq/redis_connection.rb +11 -111
  33. data/lib/sidekiq/scheduled.rb +20 -21
  34. data/lib/sidekiq/testing.rb +5 -33
  35. data/lib/sidekiq/transaction_aware_client.rb +4 -5
  36. data/lib/sidekiq/version.rb +2 -1
  37. data/lib/sidekiq/web/application.rb +21 -6
  38. data/lib/sidekiq/web/csrf_protection.rb +1 -1
  39. data/lib/sidekiq/web/helpers.rb +16 -15
  40. data/lib/sidekiq/web.rb +6 -17
  41. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  42. data/lib/sidekiq.rb +76 -274
  43. data/sidekiq.gemspec +21 -10
  44. data/web/assets/javascripts/application.js +18 -0
  45. data/web/assets/javascripts/base-charts.js +106 -0
  46. data/web/assets/javascripts/dashboard-charts.js +166 -0
  47. data/web/assets/javascripts/dashboard.js +3 -223
  48. data/web/assets/javascripts/metrics.js +117 -115
  49. data/web/assets/stylesheets/application-dark.css +4 -0
  50. data/web/assets/stylesheets/application-rtl.css +2 -91
  51. data/web/assets/stylesheets/application.css +23 -298
  52. data/web/locales/ar.yml +70 -70
  53. data/web/locales/cs.yml +62 -62
  54. data/web/locales/da.yml +60 -53
  55. data/web/locales/de.yml +65 -65
  56. data/web/locales/el.yml +2 -7
  57. data/web/locales/en.yml +76 -70
  58. data/web/locales/es.yml +68 -68
  59. data/web/locales/fa.yml +65 -65
  60. data/web/locales/fr.yml +67 -67
  61. data/web/locales/gd.yml +99 -0
  62. data/web/locales/he.yml +65 -64
  63. data/web/locales/hi.yml +59 -59
  64. data/web/locales/it.yml +53 -53
  65. data/web/locales/ja.yml +67 -69
  66. data/web/locales/ko.yml +52 -52
  67. data/web/locales/lt.yml +66 -66
  68. data/web/locales/nb.yml +61 -61
  69. data/web/locales/nl.yml +52 -52
  70. data/web/locales/pl.yml +45 -45
  71. data/web/locales/pt-br.yml +59 -69
  72. data/web/locales/pt.yml +51 -51
  73. data/web/locales/ru.yml +67 -66
  74. data/web/locales/sv.yml +53 -53
  75. data/web/locales/ta.yml +60 -60
  76. data/web/locales/uk.yml +62 -61
  77. data/web/locales/ur.yml +64 -64
  78. data/web/locales/vi.yml +67 -67
  79. data/web/locales/zh-cn.yml +20 -18
  80. data/web/locales/zh-tw.yml +10 -1
  81. data/web/views/_footer.erb +5 -2
  82. data/web/views/_job_info.erb +18 -2
  83. data/web/views/_metrics_period_select.erb +12 -0
  84. data/web/views/_paging.erb +2 -0
  85. data/web/views/_poll_link.erb +1 -1
  86. data/web/views/busy.erb +39 -28
  87. data/web/views/dashboard.erb +36 -5
  88. data/web/views/metrics.erb +33 -20
  89. data/web/views/metrics_for_job.erb +24 -43
  90. data/web/views/morgue.erb +5 -9
  91. data/web/views/queue.erb +10 -14
  92. data/web/views/queues.erb +3 -1
  93. data/web/views/retries.erb +5 -9
  94. data/web/views/scheduled.erb +12 -13
  95. metadata +51 -39
  96. data/lib/sidekiq/delay.rb +0 -43
  97. data/lib/sidekiq/extensions/action_mailer.rb +0 -48
  98. data/lib/sidekiq/extensions/active_record.rb +0 -43
  99. data/lib/sidekiq/extensions/class_methods.rb +0 -43
  100. data/lib/sidekiq/extensions/generic_proxy.rb +0 -33
  101. data/lib/sidekiq/metrics/deploy.rb +0 -47
  102. data/lib/sidekiq/worker.rb +0 -370
  103. data/web/assets/javascripts/graph.js +0 -16
  104. /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
- # require "ruby-prof"
9
+ require "ruby-prof" if ENV["PROFILE"]
8
10
  require "bundler/setup"
9
11
  Bundler.require(:default, :load_test)
10
12
 
11
- require_relative "../lib/sidekiq/cli"
12
- require_relative "../lib/sidekiq/launcher"
13
-
14
- if ENV["SIDEKIQ_REDIS_CLIENT"]
15
- Sidekiq::RedisConnection.adapter = :redis_client
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
- Sidekiq.configure_server do |config|
19
- config.options[:concurrency] = 10
20
- config.redis = {db: 13, port: 6380}
21
- # config.redis = { db: 13, port: 6380, driver: :hiredis}
22
- config.options[:queues] << "default"
23
- config.logger.level = Logger::ERROR
24
- config.average_scheduled_poll_interval = 2
25
- config.reliable! if defined?(Sidekiq::Pro)
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::Worker
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
- # brew tap shopify/shopify
42
- # brew install toxiproxy
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
- Sidekiq.redis { |c| c.flushdb }
63
- def handle_signal(launcher, sig)
64
- Sidekiq.logger.debug "Got #{sig} signal"
65
- case sig
66
- when "INT"
67
- # Handle Ctrl-C in JRuby like MRI
68
- # http://jira.codehaus.org/browse/JRUBY-4637
69
- raise Interrupt
70
- when "TERM"
71
- # Heroku sends TERM and then waits 30 seconds for process to exit.
72
- raise Interrupt
73
- when "TSTP"
74
- Sidekiq.logger.info "Received TSTP, no longer accepting new work"
75
- launcher.quiet
76
- when "TTIN"
77
- Thread.list.each do |thread|
78
- Sidekiq.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread["label"]}"
79
- if thread.backtrace
80
- Sidekiq.logger.warn thread.backtrace.join("\n")
81
- else
82
- Sidekiq.logger.warn "<no backtrace available>"
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 Process.rss
89
- `ps -o rss= -p #{Process.pid}`.chomp.to_i
90
- end
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
- iter = 10
93
- count = 10_000
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
- iter.times do
96
- arr = Array.new(count) { |idx| [idx] }
97
- Sidekiq::Client.push_bulk("class" => LoadWorker, "args" => arr)
98
- end
99
- Sidekiq.logger.error "Created #{count * iter} jobs"
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
- start = Time.now
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
- Monitoring = Thread.new do
104
- while true
105
- sleep 0.2
106
- qsize = Sidekiq.redis do |conn|
107
- conn.llen "queue:default"
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
- total = qsize
110
- # Sidekiq.logger.error("RSS: #{Process.rss} Pending: #{total}")
111
- if total == 0
112
- Sidekiq.logger.error("Done, #{iter * count} jobs in #{Time.now - start} sec")
113
- Sidekiq.logger.error("Now here's the latency for three jobs")
114
-
115
- LoadWorker.perform_async(1, Time.now.to_f)
116
- LoadWorker.perform_async(2, Time.now.to_f)
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 with_latency(latency, &block)
126
- Sidekiq.logger.error "Simulating #{latency}ms of latency between Sidekiq and redis"
127
- if latency > 0
128
- Toxiproxy[:redis].downstream(:latency, latency: latency).apply(&block)
129
- else
130
- yield
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
- begin
135
- # RubyProf::exclude_threads = [ Monitoring ]
136
- # RubyProf.start
137
- events = Sidekiq.options[:lifecycle_events][:startup]
138
- events.each(&:call)
139
- events.clear
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
data/bin/sidekiqmon CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  require "sidekiq/monitor"
4
4
 
5
+ # disable the Redis connection pool logging
6
+ Sidekiq.default_configuration.logger.level = :warn
7
+
5
8
  section = "all"
6
9
  section = ARGV[0] if ARGV.size == 1
7
10