Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 156 lines (124 sloc) 4.12 KB
#!/bin/bash -e
#
# Supervises unicorn; stopping this service prompts a graceful shutdown of the
# current unicorn instance. Sending HUP to this service causes unicorn to re-exec
# itself for upgrades etc.
#
. ../../bootstrap
PORT=$(basename "$(pwd)" |awk -F- '{print $2}')
THIS_DIR=$(pwd)
if [ -z "$PORT" ]; then
echo "usage: $0 port" 1>&2;
exit 2
fi
cat <<EOF > unicorn.rb
working_directory "$APP_DIR"
worker_processes 8
preload_app true
# Restart any workers that haven't responded in 30 seconds
timeout 30
# listen on both a Unix domain socket and a TCP port,
listen '$THIS_DIR/socket', :backlog => 64
listen '127.0.0.1:$PORT'
stderr_path "log/unicorn.stderr.log"
stdout_path "log/unicorn.stdout.log"
# http://www.rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
if GC.respond_to?(:copy_on_write_friendly=)
GC.copy_on_write_friendly = true
end
check_client_connection true
# Prevent a dangling reference to the old working directory when restarting
# See https://willj.net/2011/08/02/fixing-the-gemfile-not-found-bundlergemfilenotfound-error/
before_exec do |server|
ENV['BUNDLE_GEMFILE'] = "$APP_DIR/Gemfile"
end
before_fork do |server, worker|
# the following is highly recomended for Rails + "preload_app true"
# as there's no need for the master process to hold a connection
defined?(ActiveRecord::Base) and
ActiveRecord::Base.connection.disconnect!
##
# When sent a USR2, Unicorn will suffix its pidfile with .oldbin and
# immediately start loading up a new version of itself (loaded with a new
# version of our app). When this new Unicorn is completely loaded
# it will begin spawning workers. The first worker spawned will check to
# see if an .oldbin pidfile exists. If so, this means we've just booted up
# a new Unicorn and need to tell the old one that it can now die. To do so
# we send it a QUIT.
#
# Using this method we get 0 downtime deploys.
old_pid = 'tmp/pids/unicorn.pid.oldbin'
if File.exists?(old_pid) && server.pid != old_pid
begin
puts "Shutting down old process"
Process.kill("QUIT", File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
# someone else did our job for us
end
end
end
after_fork do |server, worker|
##
# Unicorn master loads the app then forks off workers - because of the way
# Unix forking works, we need to make sure we aren't using any of the parent's
# sockets, e.g. db connection
ActiveRecord::Base.establish_connection
# Redis and Memcached would go here but their connections are established
# on demand, so the master never opens a socket
defined?(Dalli) and Rails.cache.reset
end
EOF
function is_pid_running() {
set +e
if [ -n "$1" ] && kill -0 "$1" >/dev/null 2>&1; then
echo "yes"
fi
set -e
}
echo "My pid: $$"
CUR_PID_FILE=$APP_DIR/tmp/pids/unicorn.pid
OLD_PID_FILE=$CUR_PID_FILE.oldbin
if [ -e "$OLD_PID_FILE" ]; then
OLD_PID=$(cat "$OLD_PID_FILE")
echo "Unicorn appears to be restarting: waiting for old master ($OLD_PID) to exit"
while [ -n "$(is_pid_running "$OLD_PID")" ]; do
/bin/echo -n '.'
sleep 2
done
fi
if [ -e "$CUR_PID_FILE" ]; then
CUR_PID=$(cat "$CUR_PID_FILE")
if [ -n "$(is_pid_running "$CUR_PID")" ]; then
echo "Already running as $CUR_PID"
RUNNING=true
fi
fi
if [ ! $RUNNING ]; then
echo "Starting unicorn"
cd "$APP_DIR" && unicorn_rails -E "$RAILS_ENV" -c "$THIS_DIR/unicorn.rb" -D 2>&1
sleep 2
CUR_PID=$(cat "$CUR_PID_FILE")
fi
function restart() {
# TODO: regenerate config if this file has changed
# Tell unicorn to re-exec itself
echo "Asking unicorn to re-exec itself with USR2"
kill -USR2 "$CUR_PID"
# Wait and then exit -- after runit restarts the script, we'll
# wait for the re-exec'd process
sleep 2
echo "Restarting to supervise new unicorn"
exit
}
function graceful_shutdown() {
echo "Requesting graceful shutdown"
kill -QUIT "$CUR_PID"
}
trap restart HUP QUIT
trap graceful_shutdown INT TERM
echo "Watching for unicorn ($CUR_PID) exiting"
while [ -n "$(is_pid_running "$CUR_PID")" ]; do
/bin/echo -n '.'
sleep 2
done
echo "Unicorn has exited."