Skip to content

Commit 6894221

Browse files
Option to kill other resque-pool instances on startup
Adds the `--kill-others` command line option. When this option is set, resque-pool will send a graceful shutdown signal to all other running resque-pools. This is useful in "no downtime deploy" scenarios, where you want the pool running the new code to completely load its environment and be ready to process work *before* shutting down the old code. Once the new code is ready, it will shut down the old processes for you. See also resque#132
1 parent 13aa4b0 commit 6894221

4 files changed

Lines changed: 91 additions & 0 deletions

File tree

lib/resque/pool.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ def self.handle_winch=(bool)
8888
@handle_winch = bool
8989
end
9090

91+
def self.kill_other_pools!
92+
require 'resque/pool/killer'
93+
Resque::Pool::Killer.run
94+
end
95+
9196
def self.single_process_group=(bool)
9297
ENV["RESQUE_SINGLE_PGRP"] = !!bool ? "YES" : "NO"
9398
end
@@ -98,6 +103,7 @@ def self.single_process_group
98103
end
99104

100105
def self.run
106+
kill_other_pools! if kill_other_pools
101107
if GC.respond_to?(:copy_on_write_friendly=)
102108
GC.copy_on_write_friendly = true
103109
end
@@ -235,6 +241,7 @@ def handle_sig_queue!
235241

236242
class << self
237243
attr_accessor :term_behavior
244+
attr_accessor :kill_other_pools
238245
end
239246

240247
def graceful_worker_shutdown_and_wait!(signal)

lib/resque/pool/cli.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def parse_options
3737
opt.on('-c', '--config PATH', "Alternate path to config file") { |c| opts[:config] = c }
3838
opt.on('-a', '--appname NAME', "Alternate appname") { |c| opts[:appname] = c }
3939
opt.on("-d", '--daemon', "Run as a background daemon") { opts[:daemon] = true }
40+
opt.on("-k", '--kill-others', "Shutdown any other Resque Pools on startup") { opts[:killothers] = true }
4041
opt.on('-o', '--stdout FILE', "Redirect stdout to logfile") { |c| opts[:stdout] = c }
4142
opt.on('-e', '--stderr FILE', "Redirect stderr to logfile") { |c| opts[:stderr] = c }
4243
opt.on('--nosync', "Don't sync logfiles on every write") { opts[:nosync] = true }
@@ -130,6 +131,7 @@ def set_pool_options(opts)
130131
if opts[:spawn_delay]
131132
Resque::Pool.spawn_delay = opts[:spawn_delay] * 0.001
132133
end
134+
Resque::Pool.kill_other_pools = !!opts[:killothers]
133135
end
134136

135137
def setup_environment(opts)

lib/resque/pool/killer.rb

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
require 'open3'
2+
3+
module Resque
4+
class Pool
5+
class Killer
6+
include Logging
7+
8+
GRACEFUL_SHUTDOWN_SIGNAL=:INT
9+
10+
def self.run
11+
new.run
12+
end
13+
14+
def run
15+
my_pid = Process.pid
16+
pool_pids = all_resque_pool_processes
17+
pids_to_kill = pool_pids.reject{|pid| pid == my_pid}
18+
pids_to_kill.each do |pid|
19+
log "Pool (#{my_pid}) in kill-others mode: killing pool with pid (#{pid})"
20+
Process.kill(GRACEFUL_SHUTDOWN_SIGNAL, pid)
21+
end
22+
end
23+
24+
25+
def all_resque_pool_processes
26+
out, err, status = Open3.capture3("ps ax")
27+
unless status.success?
28+
raise "Unable to identify other pools: #{err}"
29+
end
30+
parse_pids_from_output out
31+
end
32+
33+
def parse_pids_from_output(output)
34+
pool_lines = output.split("\n").grep(/resque-pool-master/)
35+
pool_lines.map{|line|
36+
line.split.first.to_i
37+
}.select{|pid| pid > 0}
38+
end
39+
end
40+
end
41+
end

spec/killer_spec.rb

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
require 'spec_helper'
2+
require 'resque/pool/killer'
3+
4+
describe Resque::Pool::Killer do
5+
subject(:killer) { Resque::Pool::Killer.new }
6+
describe "parse pids from output" do
7+
it "returns the first column, as integer, for resque pool processes" do
8+
pids = killer.parse_pids_from_output(PS_OUTPUT)
9+
pids.should match_array [6502, 16800]
10+
end
11+
end
12+
13+
PS_OUTPUT= <<END
14+
6472 ? S 0:00 hald-addon-acpi: listening on acpid socket /var/run/acpid.socket
15+
6502 ? Sl 2:51 resque-pool-master[demo]: managing [7028, 7034]
16+
6511 ? Ss 0:00 xinetd -stayalive -pidfile /var/run/xinetd.pid
17+
6539 pts/18 Sl+ 0:31 ruby /var/www/shipit/shared/bundle/ruby/2.1.0/bin/rails console
18+
20971 ? Sl 91:51 resque-1.25.2: Waiting for ecwid
19+
14817 pts/15 Ss 0:00 -bash
20+
16334 ? Ss 0:00 sshd: foo [priv]
21+
16336 ? S 0:00 sshd: foo@pts/0
22+
16337 pts/0 Ss 0:00 -bash
23+
16342 pts/7 S+ 0:00 /bin/bash /usr/local/bin/console
24+
16480 pts/7 Sl+ 0:30 ruby /var/www/foo/shared/bundle/ruby/2.1.0/bin/rails console
25+
16486 pts/0 R+ 0:00 ps ax
26+
16800 ? Sl 5:21 resque-pool-master[demo]: managing [20728, 20734]
27+
17239 pts/19 Ss 0:00 -bash
28+
17407 pts/19 S+ 0:00 /bin/bash /usr/local/bin/console
29+
17549 pts/19 Sl+ 3:37 ruby /var/www/foo/shared/bundle/ruby/2.1.0/bin/rails console
30+
18027 ? Ss 0:00 rpc.statd -p 32765 -o 32766
31+
18114 ? S<sl 15:32 auditd
32+
19536 ? Sl 2:05 resque-scheduler-4.0.0[production]: Processing Delayed Items
33+
20004 pts/9 Ss 0:00 -bash
34+
20728 ? Sl 165:24 resque-1.25.2: Waiting for queuea,queueb
35+
20734 ? Sl 164:55 resque-1.25.2: Waiting for queueb,queuea
36+
20799 pts/10 S+ 0:00 /bin/bash /usr/local/bin/console
37+
20959 pts/10 Sl+ 0:31 ruby /var/www/foo/shared/bundle/ruby/2.1.0/bin/rails console
38+
20967 ? Sl 332:07 resque-1.25.2: queuec,queued,*
39+
END
40+
41+
end

0 commit comments

Comments
 (0)