Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: d8c41edc9b
Fetching contributors…

Cannot retrieve contributors at this time

executable file 153 lines (123 sloc) 4.156 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
#!/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 4

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', :tcp_nopush => true

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

# 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"
    unicorn_rails -E production -c $THIS_DIR/unicorn.rb -D
    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."
Something went wrong with that request. Please try again.