Skip to content

Instantly share code, notes, and snippets.

@jlecour
Created June 25, 2012 13:39
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save jlecour/2988648 to your computer and use it in GitHub Desktop.
Save jlecour/2988648 to your computer and use it in GitHub Desktop.
Unicorn configuration
#!/bin/bash
set -e
### BEGIN INIT INFO
# Provides: unicorn
# Required-Start: $all
# Required-Stop: $network $local_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start the unicorns at boot
# Description: Enable at boot time.
### END INIT INFO
# This is /etc/init.d/unicorn_init (without .sh)
# init.d script for single or multiple unicorn installations. Expects at least one .conf
# file in /etc/unicorn
#
# Modified by http://github.com/jlecour
# based on modified version by http://github.com/zewelor
# which based on modified version by http://github.com/killercup
# which based on modified version by jay@gooby.org http://github.com/jaygooby
# which is based on http://gist.github.com/308216 by http://github.com/mguterl
#
## A sample /etc/unicorn/my_app.conf
##
## APP_NAME=my_app
## RAILS_ENV=staging
## RAILS_ROOT="/home/my_user/apps/${RAILS_ENV}/${APP_NAME}/current"
## UNICORN="${RAILS_ROOT}/bin/unicorn"
## APP_USER=my_user
# This configures a unicorn master for your app at /var/apps/www/my_app/current running in
# production mode. It will read config/unicorn.rb for further set up.
#
# You should ensure different ports or sockets are set in each config/unicorn.rb if
# you are running more than one master concurrently.
#
# If you call this script without any config parameters, it will attempt to run the
# init command for all your unicorn configurations listed in /etc/unicorn/*.conf
#
# /etc/init.d/unicorn start # starts all unicorns
#
# If you specify a particular config, it will only operate on that one
#
# /etc/init.d/unicorn start my_app
DEFAULT_USER=my_user
sig () {
test -s "$PID" && kill -$1 `cat "$PID"`
}
cmd () {
case $1 in
start)
sig 0 && echo >&2 "Already running" && return 0
eval $CMD
echo "Starting"
;;
stop)
sig QUIT && echo "Stopping" && return 0
echo >&2 "Not running"
;;
force-stop)
sig TERM && echo "Forcing a stop" && return 0
echo >&2 "Not running"
;;
restart|reload|upgrade)
sig USR2 && echo Upgraded && return 0
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
eval $CMD
;;
rotate)
sig USR1 && echo rotated logs OK && return 0
echo >&2 "Couldn't rotate logs" && return 1
;;
*)
echo >&2 "Usage: $0 <start|stop|restart|upgrade|rotate|force-stop>"
exit 1
;;
esac
}
setup () {
CONFIG=$1
if [ -z $APP_NAME ]; then
echo "App name is not defined in ${CONFIG}"
return 1
fi
if [ -z $APP_USER ]; then
echo "App name is not defined in ${CONFIG}"
return 1
fi
if [ -z $RAILS_ROOT ]; then
echo "Rails root is not defined in ${CONFIG}"
return 1
fi
if [ -z $RAILS_ENV ]; then
echo "Rails environment is not defined in ${CONFIG}"
return 1
fi
# If unicorn binary was not defined in config
if [ -z $UNICORN ]; then
UNICORN="${RAILS_ROOT}/bin/unicorn"
fi
echo "Launching ${APP_NAME} (${RAILS_ROOT})"
cd $RAILS_ROOT || return 1
export PID=$RAILS_ROOT/tmp/pids/unicorn.pid
# SUDOCMD="rvmsudo -u ${APP_USER}"
SUDOCMD="sudo -u ${APP_USER}"
CMD="${SUDOCMD} RAILS_ENV=${RAILS_ENV} ${UNICORN} -E ${RAILS_ENV} -c ${RAILS_ROOT}/config/unicorn.rb -D"
return 0
}
# either run the start/stop/reload/etc command for every config under /etc/unicorn
# or just do it for a specific one
# $1 contains the start/stop/etc command
# $2 if it exists, should be the specific config we want to act on
if [ $2 ]; then
. /etc/unicorn/$2.conf
setup "/etc/unicorn/$2.conf"
if [ $? -eq 1 ]; then
exit
fi
cmd $1
else
for CONFIG in /etc/unicorn/*.conf; do
# clean variables from prev configs
unset APP_NAME
unset APP_USER
unset RAILS_ROOT
unset RAILS_ENV
unset UNICORN
# import the variables
. $CONFIG
setup $CONFIG
if [ $? -eq 1 ]; then
continue
fi
# run the start/stop/etc command
cmd $1
done
fi
# This config script is heavily inspired by GitHub
# https://github.com/blog/517-unicorn
app_directory = "/home/my_user/apps/staging/my_app/current"
worker_processes 4
working_directory app_directory
listen "unix:#{app_directory}/tmp/pids/unicorn.sock", :backlog => 1024
# listen 3000
timeout 60
user 'hh', 'hh'
File.umask(027)
preload_app true
pid "#{app_directory}/tmp/pids/unicorn.pid"
stderr_path "#{app_directory}/log/unicorn.stderr.log"
stdout_path "#{app_directory}/log/unicorn.stdout.log"
if GC.respond_to?(:copy_on_write_friendly=)
GC.copy_on_write_friendly = true
end
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 = "#{server.config[: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
# the following is recomended for Rails + "preload_app true"
# as there's no need for the master process to hold a connection
if defined?(ActiveRecord::Base)
ActiveRecord::Base.connection.disconnect!
end
end
after_fork do |server, worker|
if defined?(ActiveRecord::Base)
ActiveRecord::Base.establish_connection
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment