Skip to content

Instantly share code, notes, and snippets.

@owen2345
Last active July 28, 2022 12:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save owen2345/71537f59d98dbed4b0f0651b8a7525d1 to your computer and use it in GitHub Desktop.
Save owen2345/71537f59d98dbed4b0f0651b8a7525d1 to your computer and use it in GitHub Desktop.
Sidekiq auto finish once zero jobs to process
# Enable sidekiq auto quit feature (Allows to enable/disable this feature)
# ENV['SIDEKIQ_QUIT_WHEN_EMPTY'] = true/false
# Apply manager patch
require_relative '../lib/sidekiq_manager_patch'
require 'sidekiq/manager'
Sidekiq::Manager.send :prepend, SidekiqManagerPatch
# Add auto quit middleware
require_relative '../lib/sidekiq_quit_when_empty'
Sidekiq.configure_server do |config|
config.server_middleware do |chain|
chain.add SidekiqQuitWhenEmpty
end
end
module SidekiqManagerPatch
def start
super
SidekiqQuitWhenEmpty.kill_process if SidekiqQuitWhenEmpty.enabled? && SidekiqQuitWhenEmpty.empty_queues?
end
end
# frozen_string_literal: true
class SidekiqQuitWhenEmpty
delegate :enabled?, :empty_queues?, :kill_process, :empty_processes?, to: :class
def call(_worker, _msg, _queue)
yield
kill_process if enabled? && empty_queues? && empty_processes?
end
def self.kill_process
process = current_process
Sidekiq.logger.info "Stopping Sidekiq because all configured queues are empty: #{Sidekiq.options[:queues]}"
process ? process.stop! : Sidekiq.logger.info("Sidekiq process not found to stop")
end
def self.current_process
@retry = @retry ? @retry + 1 : 1
ps = Sidekiq::ProcessSet.new
process = ps.detect { |p| Process.pid == p['pid'] }
if !process && @retry < 5
sleep(2 * @retry)
process = current_process
end
process
end
def self.empty_queues?
(Sidekiq.options[:queues] || []).all? { |q| Sidekiq::Queue.new(q).size == 0 }
end
def self.enabled?
ENV["SIDEKIQ_QUIT_WHEN_EMPTY"].present?
end
def self.empty_processes?
queues = Sidekiq.options[:queues]
current_processes = Sidekiq::ProcessSet.new.select { |p| (queues & p['queues']).any? }
qty_workers = current_processes.map { |p| p['busy'] }.inject(&:+)
qty_workers <= 1 # take into account the current worker
end
end
bundle exec SIDEKIQ_QUIT_WHEN_EMPTY=true sidekiq -c config/sidekiq.yml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment