Created
September 9, 2011 18:46
-
-
Save ta/1207003 to your computer and use it in GitHub Desktop.
unicornctl manages your app's unicorn server in an easy manner
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require "getoptlong" | |
module UnicornCTL | |
class Controller | |
def initialize(args, argv) | |
@args = args | |
@argv = argv | |
end | |
def run! | |
commands = ["--status", "--start", "--stop", "--reload", "--restart", "--add-worker", "--del-worker", "--help"] | |
# Make sure that command makes sense | |
usage if (commands & @args.keys).length < 1 | |
raise UnicornCTL::Error, "Please specify exactly one command" if (commands & @args.keys).length != 1 | |
# Extract command and execute it | |
case (commands & @args.keys)[0] | |
when "--status" then status get_pid(@args["--pid"]) | |
when "--start" then start @args["--start"] | |
when "--stop" then stop @args["--stop"], get_pid(@args["--pid"]) | |
when "--reload" then reload get_pid(@args["--pid"]) | |
when "--restart" then restart get_pid(@args["--pid"]) | |
when "--add-worker" then add_worker get_pid(@args["--pid"]) | |
when "--del-worker" then del_worker get_pid(@args["--pid"]) | |
when "--help" then usage | |
end | |
end | |
private | |
def status(pid) | |
sysexec "PGID=`ps -o pgid= #{pid}` && ps -o pid,start,state,%cpu,%mem,command -p `pgrep -g $PGID`" | |
end | |
def start(path = "") | |
cmd = "bundle exec unicorn #{@argv.join(" ")}" | |
if !path.empty? | |
raise UnicornCTL::Error, "Directory not found: #{path}" if !Dir.exists? path | |
pwd = `pwd`.chomp | |
cmd = "cd #{path} && #{cmd} && cd #{pwd}" | |
end | |
sysexec cmd | |
end | |
def stop(arg, pid) | |
raise UnicornCTL::Error, "Invalid argument for command --stop: #{arg}" unless !!["", "force"].index(arg) | |
sysexec arg == "force" ? "kill -TERM #{pid}" : "kill -QUIT #{pid}" | |
end | |
def reload(pid) | |
sysexec "kill -HUP #{pid}" | |
end | |
def restart(pid) | |
sysexec "kill -USR2 #{pid}" | |
end | |
def add_worker(pid) | |
sysexec "kill -TTIN #{pid}" | |
end | |
def del_worker(pid) | |
sysexec "kill -TTOU #{pid}" | |
end | |
def get_pid(arg) | |
if arg | |
# Argument is a pid | |
pid = arg if !!(arg =~ /^[1-9]([0-9]*)?$/) | |
# Argument is a pid file | |
if !pid | |
raise UnicornCTL::Error, "No such pid file: #{arg}" unless File.exists?(arg) | |
pid = File.read(arg, 5).chomp | |
end | |
else | |
raise UnicornCTL::Error, "No such pid file: unicorn.pid" unless File.exists?("unicorn.pid") | |
pid = File.read("unicorn.pid", 5).chomp | |
end | |
# Validate pid | |
raise UnicornCTL::Error, "Corrupt pid found: #{pid}" unless !!(pid =~ /^[1-9]([0-9]*)?$/) | |
%x[ps -p #{pid} > /dev/null 2>&1] | |
raise UnicornCTL::Error, "No process with id: #{pid}" unless $?.exitstatus == 0 | |
pid | |
end | |
def dry? | |
!!@args["--dry"] | |
end | |
def sysexec(cmd) | |
if dry? | |
puts "Would have run command: #{cmd}" | |
else | |
exec cmd | |
end | |
end | |
def usage | |
puts <<-EOF | |
USAGE: | |
unicornctl COMMAND [OPTIONS] | |
COMMANDS: | |
--status | |
Show status and other information about the master process | |
--start [-- [unicorn options]] | |
Starts unicorn - add unicorn specific options after "--" | |
--stop [force] | |
Stops unicorn - add "force" argument to kill workers without allowing | |
them to finish their current request. | |
--reload | |
Reloads config file and gracefully restart all workers | |
--restart | |
Restarts unicorn by replacing the running binary with a new one without | |
loosing any incoming connections | |
--add-worker | |
Increase number of workers by one | |
--del-worker | |
Decrease number of workers by one | |
--help | |
Show this help message | |
OPTIONS: | |
--pid (PID|PIDFILE) | |
Unicorn pid of the master process or path to unicorn pid file - used with | |
--status, --stop, --reload, --restart, --add-worker and --del-worker. | |
If this option is omitted, unicornctl will look for a "unicorn.pid" file | |
in the current directory. | |
--dry | |
If set commands are just send to stdout - not executed | |
EOF | |
exit 1 | |
end | |
end | |
class Error < StandardError; end | |
end | |
begin | |
opts = GetoptLong.new( | |
[ '--help', GetoptLong::NO_ARGUMENT ], | |
[ '--status', GetoptLong::NO_ARGUMENT ], | |
[ '--start', GetoptLong::OPTIONAL_ARGUMENT ], | |
[ '--stop', GetoptLong::OPTIONAL_ARGUMENT ], | |
[ '--reload', GetoptLong::NO_ARGUMENT ], | |
[ '--restart', GetoptLong::NO_ARGUMENT ], | |
[ '--add-worker', GetoptLong::NO_ARGUMENT ], | |
[ '--del-worker', GetoptLong::NO_ARGUMENT ], | |
[ '--pid', GetoptLong::REQUIRED_ARGUMENT ], | |
[ '--dry', GetoptLong::NO_ARGUMENT ] | |
) | |
opts.quiet = true | |
args = {} | |
opts.each { |opt,arg| args[opt] = arg } | |
UnicornCTL::Controller.new(args, ARGV).run! | |
rescue UnicornCTL::Error, GetoptLong::Error => e | |
puts "Error: " + e.message | |
rescue => e | |
puts e.message | |
puts e.backtrace | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment