PAB's blog - Tag - init2022-11-19T07:02:34+00:00urn:md5:5926f7e05a689ea9af53f3d15057feb6DotclearInit script for Rails app served by Unicorn with RVMurn:md5:bd3dbdb2ebfaa5c074525571d6be0d892016-10-22T07:49:00+02:002018-05-23T08:42:42+02:00Pierre-Alain Binitlinuxrailsunicorn <p>Here is an init script for a Rails app served by Unicorn with RVM.</p>
<pre>
#!/bin/bash
### BEGIN INIT INFO
# Provides: APP_NAME, with Unicorn serving
# Required-Start: $all
# Required-Stop: $network $local_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start APP_NAME unicorn at boot
# Description: Enable APP_NAME at boot time.
### END INIT INFO
set -u
set -e
# Change these to match your app:
APP_NAME="APP_NAME"
APP_ROOT="/path/to/app"
PID="/path/to/app/tmp/pids/unicorn.pid"
ENV="production"
RVM="2.3.0@gemset"
USER="user"
UNICORN_OPTS="-D -E $ENV -c $APP_ROOT/config/unicorn.rb"
SET_PATH="cd $APP_ROOT; rvm use $RVM > /dev/null;"
CMD="$SET_PATH unicorn $UNICORN_OPTS"
old_pid="$PID.oldbin"
cd $APP_ROOT || exit 1
sig () {
test -s "$PID" && kill -$1 `cat $PID`
}
oldsig () {
test -s $old_pid && kill -$1 `cat $old_pid`
}
start () {
echo "Starting $APP_NAME unicorn..."
sig 0 && echo -e >&2 "\e[31mAlready running" && exit 0
su - $USER -c "$CMD" > /dev/null
echo -e "$APP_NAME has \e[32mstarted\e[0m, PID is `cat $PID`"
}
stop () {
echo "Stopping $APP_NAME unicorn (signal QUIT)..."
sig QUIT && echo -e "$APP_NAME has \e[32mstopped" && exit 0
echo >&2 "Not running"
}
case ${1-help} in
start)
start
;;
stop)
stop
;;
force-stop)
echo "Force stopping $APP_NAME unicorn (signal TERM)..."
sig TERM && echo "$APP_NAME has stopped" &&exit 0
echo -e >&2 "\e[31mNot running"
;;
reload)
echo "Reloading $APP_NAME unicorn (signal USR2)..."
sig USR2 && echo -e "$APP_NAME has \e[32mreloaded" && exit 0
echo -e >&2 "\e[31mCouldn't reload\e[0m, starting instead"
start
;;
status)
sig 0 && echo -e "$APP_NAME \e[32mrunning\e[0m with PID `cat $PID`" && exit 0
echo -e "$APP_NAME is \e[31mnot running!"
;;
*)
echo >&2 "Usage: $0 <start|stop|reload|status|force-stop>"
exit 0
;;
esac
</pre>
<p>Beware that the reload calls USR2. In the documentation of Unicorn, it is said that USR2 should be followed by QUIT. Otherwise the good signal to reload is HUP.</p>
<p>However, I use the following unicorn.rb config file inspired from Github's and you will see that it specifies that the new instance of Unicorn shall send a QUIT signal to the old one!</p>
<pre>
rails_root = "/path/to/app"
rails_env = ENV['RAILS_ENV'] || 'production'
# 4 workers, may be changed to 1 for the tests
worker_processes (rails_env == 'production' ? 4 : 1)
# Load rails+app into the master before forking workers
# for super-fast worker spawn times
preload_app true
# Restart any workers that haven't responded in 30 seconds
timeout 30
before_fork do |server, worker|
##
# 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 = rails_root + '/tmp/pids/unicorn.pid.oldbin'
if File.exists?(old_pid) && server.pid != old_pid
begin
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
end
</pre>