#!/usr/bin/env ruby # Quiet some warnings we see when running in warning mode: # RUBYOPT=-w bundle exec sidekiq $TESTING = false #require 'ruby-prof' require_relative '../lib/sidekiq/cli' require_relative '../lib/sidekiq/launcher' include Sidekiq::Util # brew tap shopify/shopify # brew install toxiproxy # gem install toxiproxy require 'toxiproxy' # simulate a non-localhost network for realer-world conditions. # adding 1ms of network latency has an ENORMOUS impact on benchmarks Toxiproxy.populate([{ "name": "redis", "listen": "127.0.0.1:6380", "upstream": "127.0.0.1:6379" }]) Sidekiq.configure_server do |config| config.redis = { db: 13, port: 6380 } #config.redis = { db: 13 } config.options[:queues] << 'default' config.logger.level = Logger::ERROR config.average_scheduled_poll_interval = 2 end class LoadWorker include Sidekiq::Worker sidekiq_options retry: 1 sidekiq_retry_in do |x| 1 end def perform(idx) #raise idx.to_s if idx % 100 == 1 end end # brew tap shopify/shopify # brew install toxiproxy # gem install toxiproxy require 'toxiproxy' # simulate a non-localhost network for realer-world conditions. # adding 1ms of network latency has an ENORMOUS impact on benchmarks Toxiproxy.populate([{ "name": "redis", "listen": "127.0.0.1:6380", "upstream": "127.0.0.1:6379" }]) self_read, self_write = IO.pipe %w(INT TERM USR1 USR2 TTIN).each do |sig| begin trap sig do self_write.puts(sig) end rescue ArgumentError puts "Signal #{sig} not supported" end end Sidekiq.redis {|c| c.flushdb} def handle_signal(launcher, sig) Sidekiq.logger.debug "Got #{sig} signal" case sig when 'INT' # Handle Ctrl-C in JRuby like MRI # http://jira.codehaus.org/browse/JRUBY-4637 raise Interrupt when 'TERM' # Heroku sends TERM and then waits 10 seconds for process to exit. raise Interrupt when 'USR1' Sidekiq.logger.info "Received USR1, no longer accepting new work" launcher.quiet when 'USR2' if Sidekiq.options[:logfile] Sidekiq.logger.info "Received USR2, reopening log file" Sidekiq::Logging.reopen_logs end when 'TTIN' Thread.list.each do |thread| Sidekiq.logger.warn "Thread TID-#{thread.object_id.to_s(36)} #{thread['label']}" if thread.backtrace Sidekiq.logger.warn thread.backtrace.join("\n") else Sidekiq.logger.warn "" end end end end def Process.rss `ps -o rss= -p #{Process.pid}`.chomp.to_i end iter = 10 count = 10_000 iter.times do arr = Array.new(count) do [] end count.times do |idx| arr[idx][0] = idx end Sidekiq::Client.push_bulk('class' => LoadWorker, 'args' => arr) end Sidekiq.logger.error "Created #{count*iter} jobs" Monitoring = Thread.new do watchdog("monitor thread") do while true sleep 2 qsize, retries = Sidekiq.redis do |conn| conn.pipelined do conn.llen "queue:default" conn.zcard "retry" end end.map(&:to_i) total = qsize + retries #GC.start Sidekiq.logger.error("RSS: #{Process.rss} Pending: #{total}") if total == 0 Sidekiq.logger.error("Done") exit(0) end end end end begin #RubyProf::exclude_threads = [ Monitoring ] #RubyProf.start Sidekiq.logger.error "Simulating 1ms of latency between Sidekiq and redis" Toxiproxy[:redis].downstream(:latency, latency: 1).apply do launcher = Sidekiq::Launcher.new(Sidekiq.options) launcher.run while readable_io = IO.select([self_read]) signal = readable_io.first[0].gets.strip handle_signal(launcher, signal) end end rescue SystemExit => e #Sidekiq.logger.error("Profiling...") #result = RubyProf.stop #printer = RubyProf::GraphHtmlPrinter.new(result) #printer.print(File.new("output.html", "w"), :min_percent => 1) # normal rescue => e raise e if $DEBUG STDERR.puts e.message STDERR.puts e.backtrace.join("\n") exit 1 end