poise/application_ruby — pull request #51 by JeanMertz (2014-02-06 13:56:37+00:00)
Title: Unicorn: allow for custom runit templates (unicorn zero-downtime)

This change, combined with the below custom template/config allowed for zero-downtime deployments with unicorn:

**recipes/my_app.rb**

```ruby
application 'unicorn_zero_downtime' do

# ...

unicorn do
runit_cookbook('')
runit_options(pid: '/path/to/unicorn.pid')

restart_command Proc.new do
execute 'restart_unicorn' do
command "/usr/bin/sv 2 #{app_name}"
user 'root'
end
end
end
end
```

**templates/default/sv-unicorn-run.erb** (modified from [this gist][], thanks @czarneckid)

[this gist]: https://gist.github.com/czarneckid/4639793

```bash
#!/bin/bash
#
# This file is managed by Chef, using the <%= node.name %> cookbook.
# Editing this file by hand is highly discouraged!
#
exec 2>&1

#
# Since unicorn creates a new pid on restart/reload, it needs a little extra love to
# manage with runit. Instead of managing unicorn directly, we simply trap signal calls
# to the service and redirect them to unicorn directly.
#

function is_unicorn_alive {
set +e
if [ -n $1 ] && kill -0 $1 >/dev/null 2>&1; then
echo "yes"
fi
set -e
}

echo "Service PID: $$"

CUR_PID_FILE=<%= @options['pid'] %>
OLD_PID_FILE=$CUR_PID_FILE.oldbin

if [ -e $OLD_PID_FILE ]; then
OLD_PID=$(cat $OLD_PID_FILE)
echo "Waiting for existing master ($OLD_PID) to exit"
while [ -n "$(is_unicorn_alive $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_unicorn_alive $CUR_PID)" ]; then
echo "Unicorn master already running. PID: $CUR_PID"
RUNNING=true
fi
fi

if [ ! $RUNNING ]; then
echo "Starting unicorn"
cd <%= @options[:app].path %>/current

# You need to daemonize the unicorn process, http://unicorn.bogomips.org/unicorn_rails_1.html
<%= @options[:bundler] ? "#{@options[:bundle_command]} exec" : '' %> <%= @options[:smells_like_rack] ? 'unicorn' : 'unicorn_rails' %> -c /etc/unicorn/<%= @options[:app].application.name %>.rb -E <%= @options[:rails_env] %> -D
sleep 3
CUR_PID=$(cat $CUR_PID_FILE)
fi

function restart {
echo "Initialize new master with USR2"
kill -USR2 $CUR_PID
# Make runit restart to pick up new unicorn pid
sleep 2
echo "Restarting service to capture new pid"
exit
}

function graceful_shutdown {
echo "Initializing graceful shutdown"
kill -QUIT $CUR_PID
}

function unicorn_interrupted {
echo "Unicorn process interrupted. Possibly a runit thing?"
}

trap restart HUP QUIT USR2 INT
trap graceful_shutdown TERM KILL
trap unicorn_interrupted ALRM

echo "Waiting for current master to die. PID: ($CUR_PID)"
while [ -n "$(is_unicorn_alive $CUR_PID)" ]; do
/bin/echo -n '.'
sleep 2
done
```