require 'optparse'
require 'net/http'
require 'uri'
if RUBY_PLATFORM =~ /mswin32/ then abort("Reaper is only for Unix") end
class ProgramProcess
class << self
def process_keywords(action, *keywords)
processes = keywords.collect { |keyword| find_by_keyword(keyword) }.flatten
if processes.empty?
puts "Couldn't find any process matching: #{keywords.join(" or ")}"
else
processes.each do |process|
puts "#{action.capitalize}ing #{process}"
process.send(action)
end
end
end
def find_by_keyword(keyword)
process_lines_with_keyword(keyword).split("\n").collect { |line|
next if line.include?("inq") || line.include?("ps -ax") || line.include?("grep")
pid, *command = line.split
new(pid, command.join(" "))
}.compact
end
private
def process_lines_with_keyword(keyword)
`ps -ax -o 'pid command' | grep #{keyword}`
end
end
def initialize(pid, command)
@pid, @command = pid, command
end
def find
end
def reload
`kill -s HUP #{@pid}`
end
def graceful
`kill -s TERM #{@pid}`
end
def kill
`kill -9 #{@pid}`
end
def usr1
`kill -s USR1 #{@pid}`
end
def restart
`kill -s USR2 #{@pid}`
end
def to_s
"[#{@pid}] #{@command}"
end
end
OPTIONS = {
:action => "restart",
:dispatcher => File.expand_path(RAILS_ROOT + '/public/dispatch.fcgi')
}
ARGV.options do |opts|
opts.banner = "Usage: reaper [options]"
opts.separator ""
opts.on <<-EOF
Description:
The reaper is used to restart, reload, gracefully exit, and forcefully exit FCGI processes
running a Rails Dispatcher. This is commonly done when a new version of the application
is available, so the existing processes can be updated to use the latest code.
The reaper actions are:
* restart : Restarts the application by reloading both application and framework code
* reload : Only reloads the application, but not the framework (like the development environment)
* graceful: Marks all of the processes for exit after the next request
* kill : Forcefully exists all processes regardless of whether they're currently serving a request
Restart is the most common and default action.
Examples:
reaper # restarts the default dispatcher
reaper -a reload
reaper -a exit -d /my/special/dispatcher.fcgi
EOF
opts.on(" Options:")
opts.on("-a", "--action=name", "reload|graceful|kill (default: #{OPTIONS[:action]})", String) { |OPTIONS[:action]| }
opts.on("-d", "--dispatcher=path", "default: #{OPTIONS[:dispatcher]}", String) { |OPTIONS[:dispatcher]| }
opts.separator ""
opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
opts.parse!
end
ProgramProcess.process_keywords(OPTIONS[:action], OPTIONS[:dispatcher])