Skip to content

Instantly share code, notes, and snippets.

@ericluo
Forked from karmi/workers.rake
Created January 21, 2014 00:47
Show Gist options
  • Select an option

  • Save ericluo/8532287 to your computer and use it in GitHub Desktop.

Select an option

Save ericluo/8532287 to your computer and use it in GitHub Desktop.

Revisions

  1. @karmi karmi revised this gist Feb 13, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion workers.rake
    Original file line number Diff line number Diff line change
    @@ -151,7 +151,7 @@ namespace :workers do
    end

    desc "Kill ALL workers on this machine"
    task :kilall do
    task :killall do
    require 'resque'
    Resque::Worker.all.each do |worker|
    puts "Shutting down worker #{worker}"
  2. @karmi karmi revised this gist Nov 30, 2010. 1 changed file with 49 additions and 50 deletions.
    99 changes: 49 additions & 50 deletions workers.rake
    Original file line number Diff line number Diff line change
    @@ -11,55 +11,47 @@ namespace :workers do
    #
    # Each worker is being run in their own separate process (_not_ thread).
    #
    # First started group of workers is considered "main group", whose PIDs are
    # saved into pid files in tmp/pids/resque/*.pid. When any worker from this
    # group exits, it kills the master process as well.
    # This is because we want to monitor this group as a whole.
    #
    # Any subsequently started group is considered an "ad hoc" group. Their PIDs
    # are not saved. When any worker from this group exits, the master process
    # and other workers continue running. This is because we don't care about
    # workers in this group.
    #
    # On clean shutdown (SIGINT / Ctrl-C, SIGQUIT, SIGTERM), the task will clean
    # after itself: kill its workers and delete PID files, when appropriate. It
    # will deal fine with already dead workers.
    #
    #
    # Default options like COUNT can and should be over-ridden when invoking, of course:
    #
    #
    # $ rake workers:start COUNT=10 QUEUE=my_queue
    #
    #
    # To daemonize, simply run with nohup:
    #
    # $ nohup rake workers:start > log/workers.log 2>&1 &
    #
    # You can set up your monitoring tool to watch for process with PID
    #
    # You can and should set up your monitoring tool to watch for process with PID
    # from `cat tmp/pids/resque/master.pid`.
    #
    # For proper monitoring of _individual_ workers, use provided examples for God or Monit:
    # http://github.com/defunkt/resque/blob/master/examples/.
    #
    #
    # A task for killing all workers on the machine (`rake workers:killall`) is also provided,
    # for pruning orphaned workers etc.
    #
    # NOTE: There are couple of reasons why we needed something like this and didn't
    # find it provided for in Resque.
    #
    # First, we wanted to have one single Rake task to launch multiple workers
    # in production _and_ in development. This was inspired by the bundled
    # `rake resque:workers` task.
    #
    # Second, we wanted operations guys to simply guarantee that this Rake task
    # is running and that's all. We would rather configure and tune everything
    # (like the number of workers) inside the task, then bother them.
    #
    # Third, we wanted an easy way how to very easily launch multiple workers
    # in production (on sudden spikes in jobs, etc), just by SSH-ing
    # to the box and running the "one and only" task.

    desc "Run and manage group of Resque workers with some default options"
    task :start => :environment do

    # - CONFIGURATION ----
    ENV['QUEUE'] ||= '*'
    ENV['COUNT'] ||= '3'
    # --------------------

    def queue
    ENV['QUEUE']
    end

    def count
    ENV['COUNT']
    end

    def Process.exists?(pid)
    kill(0, pid.to_i) rescue false
    end
    @@ -68,16 +60,20 @@ namespace :workers do
    @pid_directory ||= Rails.root.join('tmp', 'pids', "resque")
    end

    def main_group_master_pid
    File.read pid_directory.join('master.pid').to_s rescue nil
    def pid_directory_for_group
    @pid_directory_for_group ||= Rails.root.join('tmp', 'pids', "resque", queue)
    end

    def group_master_pid
    File.read pid_directory.join("#{queue}.pid").to_s rescue nil
    end

    def main_group?
    !main_group_master_pid || main_group_master_pid.to_s == Process.pid.to_s
    def group?
    !group_master_pid || group_master_pid.to_s == Process.pid.to_s
    end

    def main_group_running?
    Process.exists?(main_group_master_pid)
    def group_running?
    Process.exists?(group_master_pid)
    end

    def kill_worker(pid)
    @@ -91,43 +87,43 @@ namespace :workers do
    @pids.each { |pid| kill_worker(pid) }
    end

    def kill_workers_and_remove_pids_for_main_group
    Dir.glob(pid_directory.join('worker_*.pid').to_s) do |pidfile|
    def kill_workers_and_remove_pids_for_group
    Dir.glob(pid_directory_for_group.join('worker_*.pid').to_s) do |pidfile|
    begin
    pid = pidfile[/(\d+)\.pid/, 1].to_i
    kill_worker(pid)
    ensure
    FileUtils.rm pidfile, :force => true
    end
    end
    FileUtils.rm pid_directory.join('master.pid').to_s if main_group_master_pid
    if group_master_pid
    FileUtils.rm pid_directory.join("#{queue}.pid").to_s
    FileUtils.rm_rf pid_directory_for_group.to_s
    end
    end

    def shutdown
    puts "\n*** Exiting"
    if main_group?
    kill_workers_and_remove_pids_for_main_group
    if group?
    kill_workers_and_remove_pids_for_group
    else
    kill_workers
    end
    exit(0)
    end

    # Clean up after dead main group from before -- and become one
    unless main_group_running?
    puts "--- Cleaning up after previous main group (PID: #{main_group_master_pid})"
    kill_workers_and_remove_pids_for_main_group
    # Clean up after dead group from before -- and become one
    unless group_running?
    puts "--- Cleaning up after previous group (PID: #{group_master_pid})"
    kill_workers_and_remove_pids_for_group
    end

    # Handle exit
    trap('INT') { shutdown }
    trap('QUIT') { shutdown }
    trap('TERM') { shutdown }

    # - CONFIGURATION ----
    ENV['QUEUE'] ||= '*'
    ENV['COUNT'] ||= '3'
    # --------------------
    trap('KILL') { shutdown }
    trap('SIGKILL') { shutdown }

    puts "=== Launching #{ENV['COUNT']} worker(s) on '#{ENV['QUEUE']}' queue(s) with PID #{Process.pid}"

    @@ -137,12 +133,15 @@ namespace :workers do
    @pids << Process.fork { Rake::Task['resque:work'].invoke }
    end

    if main_group?
    if group?
    # Make sure we have directory for pids
    FileUtils.mkdir_p pid_directory.to_s
    FileUtils.mkdir_p pid_directory_for_group.to_s
    # Create PID files for workers
    File.open( pid_directory.join("master.pid").to_s, 'w' ) do |f| f.write Process.pid end
    @pids.each do |pid| File.open( pid_directory.join("worker_#{pid}.pid").to_s, 'w' ) { |f| f.write pid } end
    File.open( pid_directory.join("#{queue}.pid").to_s, 'w' ) do |f| f.write Process.pid end
    @pids.each do |pid|
    File.open( pid_directory_for_group.join("worker_#{pid}.pid").to_s, 'w' ) { |f| f.write pid }
    end
    # Stay in foreground, if any of our workers dies, we'll get killed so Monit/God etc can come to the resq^Hcue
    Process.wait
    else
  3. @karmi karmi revised this gist Jul 23, 2010. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions workers.rake
    Original file line number Diff line number Diff line change
    @@ -39,6 +39,9 @@ namespace :workers do
    # For proper monitoring of _individual_ workers, use provided examples for God or Monit:
    # http://github.com/defunkt/resque/blob/master/examples/.
    #
    # A task for killing all workers on the machine (`rake workers:killall`) is also provided,
    # for pruning orphaned workers etc.
    #
    # NOTE: There are couple of reasons why we needed something like this and didn't
    # find it provided for in Resque.
    #
  4. @karmi karmi revised this gist Jul 23, 2010. 1 changed file with 10 additions and 9 deletions.
    19 changes: 10 additions & 9 deletions workers.rake
    Original file line number Diff line number Diff line change
    @@ -13,11 +13,11 @@ namespace :workers do
    #
    # First started group of workers is considered "main group", whose PIDs are
    # saved into pid files in tmp/pids/resque/*.pid. When any worker from this
    # group exits, it takes the the master process down as well.
    # group exits, it kills the master process as well.
    # This is because we want to monitor this group as a whole.
    #
    # Any subsequently started groups are considered ad hoc. Their PIDs
    # are not saved. When workers from this group exit, the master process
    # Any subsequently started group is considered an "ad hoc" group. Their PIDs
    # are not saved. When any worker from this group exits, the master process
    # and other workers continue running. This is because we don't care about
    # workers in this group.
    #
    @@ -31,27 +31,28 @@ namespace :workers do
    #
    # To daemonize, simply run with nohup:
    #
    # nohup rake workers:start > log/workers.log 2>&1 &
    # $ nohup rake workers:start > log/workers.log 2>&1 &
    #
    # You can set up your monitoring tool to watch for process with PID
    # from `cat tmp/pids/resque/master.pid`.
    #
    # For proper monitoring of workers, use provided examples for God or Monit:
    # For proper monitoring of _individual_ workers, use provided examples for God or Monit:
    # http://github.com/defunkt/resque/blob/master/examples/.
    #
    # NOTE: There are couple of reasons why we needed something like this and didn't
    # find provided in Resque.
    # find it provided for in Resque.
    #
    # First, we wanted to have one single Rake task to launch multiple workers
    # in production and in development. This was inspired by the bundled
    # in production _and_ in development. This was inspired by the bundled
    # `rake resque:workers` task.
    #
    # Second, we wanted operations guys to simply guarantee that this Rake task
    # is running and that's all. We would rather configure and tune everything
    # (like the number of workers) inside the task.
    # (like the number of workers) inside the task, then bother them.
    #
    # Third, we wanted an easy way how to very easily launch multiple workers
    # in production (on sudden spikes in jobs, etc).
    # in production (on sudden spikes in jobs, etc), just by SSH-ing
    # to the box and running the "one and only" task.

    desc "Run and manage group of Resque workers with some default options"
    task :start => :environment do
  5. @karmi karmi revised this gist Jul 23, 2010. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions workers.rake
    Original file line number Diff line number Diff line change
    @@ -139,8 +139,7 @@ namespace :workers do
    # Create PID files for workers
    File.open( pid_directory.join("master.pid").to_s, 'w' ) do |f| f.write Process.pid end
    @pids.each do |pid| File.open( pid_directory.join("worker_#{pid}.pid").to_s, 'w' ) { |f| f.write pid } end
    # Stay in foreground, if any of our workers dies, we'll get killed so
    # Monit/God etc can come to the resq^Hcue
    # Stay in foreground, if any of our workers dies, we'll get killed so Monit/God etc can come to the resq^Hcue
    Process.wait
    else
    # Stay in foreground, if any of our workers dies, continue running
  6. @karmi karmi revised this gist Jul 22, 2010. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion workers.rake
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    # Rake taks to launch multiple Resque workers in development/production with simple management included
    # Rake task to launch multiple Resque workers in development/production with simple management included

    require 'resque/tasks' # Require Resque tasks

  7. @karmi karmi revised this gist Jul 22, 2010. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions workers.rake
    Original file line number Diff line number Diff line change
    @@ -13,10 +13,10 @@ namespace :workers do
    #
    # First started group of workers is considered "main group", whose PIDs are
    # saved into pid files in tmp/pids/resque/*.pid. When any worker from this
    # group exits, the master process exits. This is because we want to
    # monitor this group as a whole.
    # group exits, it takes the the master process down as well.
    # This is because we want to monitor this group as a whole.
    #
    # Any subsequently started groups are considered "free agents", whose PIDs
    # Any subsequently started groups are considered ad hoc. Their PIDs
    # are not saved. When workers from this group exit, the master process
    # and other workers continue running. This is because we don't care about
    # workers in this group.
  8. @karmi karmi created this gist Jul 22, 2010.
    161 changes: 161 additions & 0 deletions workers.rake
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,161 @@
    # Rake taks to launch multiple Resque workers in development/production with simple management included

    require 'resque/tasks' # Require Resque tasks

    namespace :workers do

    # = $ rake workers:start
    #
    # Launch multiple Resque workers with the Rails environment loaded,
    # so they have access to your models, etc.
    #
    # Each worker is being run in their own separate process (_not_ thread).
    #
    # First started group of workers is considered "main group", whose PIDs are
    # saved into pid files in tmp/pids/resque/*.pid. When any worker from this
    # group exits, the master process exits. This is because we want to
    # monitor this group as a whole.
    #
    # Any subsequently started groups are considered "free agents", whose PIDs
    # are not saved. When workers from this group exit, the master process
    # and other workers continue running. This is because we don't care about
    # workers in this group.
    #
    # On clean shutdown (SIGINT / Ctrl-C, SIGQUIT, SIGTERM), the task will clean
    # after itself: kill its workers and delete PID files, when appropriate. It
    # will deal fine with already dead workers.
    #
    # Default options like COUNT can and should be over-ridden when invoking, of course:
    #
    # $ rake workers:start COUNT=10 QUEUE=my_queue
    #
    # To daemonize, simply run with nohup:
    #
    # nohup rake workers:start > log/workers.log 2>&1 &
    #
    # You can set up your monitoring tool to watch for process with PID
    # from `cat tmp/pids/resque/master.pid`.
    #
    # For proper monitoring of workers, use provided examples for God or Monit:
    # http://github.com/defunkt/resque/blob/master/examples/.
    #
    # NOTE: There are couple of reasons why we needed something like this and didn't
    # find provided in Resque.
    #
    # First, we wanted to have one single Rake task to launch multiple workers
    # in production and in development. This was inspired by the bundled
    # `rake resque:workers` task.
    #
    # Second, we wanted operations guys to simply guarantee that this Rake task
    # is running and that's all. We would rather configure and tune everything
    # (like the number of workers) inside the task.
    #
    # Third, we wanted an easy way how to very easily launch multiple workers
    # in production (on sudden spikes in jobs, etc).

    desc "Run and manage group of Resque workers with some default options"
    task :start => :environment do

    def Process.exists?(pid)
    kill(0, pid.to_i) rescue false
    end

    def pid_directory
    @pid_directory ||= Rails.root.join('tmp', 'pids', "resque")
    end

    def main_group_master_pid
    File.read pid_directory.join('master.pid').to_s rescue nil
    end

    def main_group?
    !main_group_master_pid || main_group_master_pid.to_s == Process.pid.to_s
    end

    def main_group_running?
    Process.exists?(main_group_master_pid)
    end

    def kill_worker(pid)
    Process.kill("QUIT", pid)
    puts "Killed worker with PID #{pid}"
    rescue Errno::ESRCH => e
    puts " STALE worker with PID #{pid}"
    end

    def kill_workers
    @pids.each { |pid| kill_worker(pid) }
    end

    def kill_workers_and_remove_pids_for_main_group
    Dir.glob(pid_directory.join('worker_*.pid').to_s) do |pidfile|
    begin
    pid = pidfile[/(\d+)\.pid/, 1].to_i
    kill_worker(pid)
    ensure
    FileUtils.rm pidfile, :force => true
    end
    end
    FileUtils.rm pid_directory.join('master.pid').to_s if main_group_master_pid
    end

    def shutdown
    puts "\n*** Exiting"
    if main_group?
    kill_workers_and_remove_pids_for_main_group
    else
    kill_workers
    end
    exit(0)
    end

    # Clean up after dead main group from before -- and become one
    unless main_group_running?
    puts "--- Cleaning up after previous main group (PID: #{main_group_master_pid})"
    kill_workers_and_remove_pids_for_main_group
    end

    # Handle exit
    trap('INT') { shutdown }
    trap('QUIT') { shutdown }
    trap('TERM') { shutdown }

    # - CONFIGURATION ----
    ENV['QUEUE'] ||= '*'
    ENV['COUNT'] ||= '3'
    # --------------------

    puts "=== Launching #{ENV['COUNT']} worker(s) on '#{ENV['QUEUE']}' queue(s) with PID #{Process.pid}"

    # Launch workers in separate processes, saving their PIDs
    @pids = []
    ENV['COUNT'].to_i.times do
    @pids << Process.fork { Rake::Task['resque:work'].invoke }
    end

    if main_group?
    # Make sure we have directory for pids
    FileUtils.mkdir_p pid_directory.to_s
    # Create PID files for workers
    File.open( pid_directory.join("master.pid").to_s, 'w' ) do |f| f.write Process.pid end
    @pids.each do |pid| File.open( pid_directory.join("worker_#{pid}.pid").to_s, 'w' ) { |f| f.write pid } end
    # Stay in foreground, if any of our workers dies, we'll get killed so
    # Monit/God etc can come to the resq^Hcue
    Process.wait
    else
    # Stay in foreground, if any of our workers dies, continue running
    Process.waitall
    end
    end

    desc "Kill ALL workers on this machine"
    task :kilall do
    require 'resque'
    Resque::Worker.all.each do |worker|
    puts "Shutting down worker #{worker}"
    host, pid, queues = worker.id.split(':')
    Process.kill("QUIT", pid.to_i)
    end
    end

    end