Skip to content

Instantly share code, notes, and snippets.

@ganta
Created July 8, 2012 11:37
Show Gist options
  • Save ganta/3070613 to your computer and use it in GitHub Desktop.
Save ganta/3070613 to your computer and use it in GitHub Desktop.
Unicorn init.d script with support for different rbenv gemsets
First download unicorn file to /etc/init.d/unicorn and chmod +x.
Mkdir /etc/unicorn/
Create file for your application for example /etc/unicorn/my_app.conf
Script will guess all needed values, so you can only create empty file my_app.conf.
Default values ( "my_app" is taken from .conf file name WITHOUT .conf extension. ):
* RAILS_ROOT=/home/my_app/www/current ( capistrano directories ).
* RAILS_ENV=production.
* APP_USER=my_app ( used to run unicorn as that user )
* UNICORN unicorn_rails
Every variable can be overwritten in .conf file.
Script assumes unicorn config will be in RAILS_ROOT/config/unicorn/RAILS_ENV.rb
( for example /home/my_app/www/current/config/unicorn/production.rb )
It should be used with capistrano deployment as some paths are made for
its directory layout: "current" and "shared" dirs.
# RAILS_ROOT/config/unicorn.rb
# Search for "# SET ME!" and replace these with your own settings!.
HOW_DEEP_WE_R_FROM_RAILS_ROOT = "../.."
# Set environment to development unless something else is specified
RAILS_ROOT = File.expand_path(HOW_DEEP_WE_R_FROM_RAILS_ROOT, File.dirname(__FILE__))
SHARED_PATH = File.expand_path('../shared', RAILS_ROOT)
ENV['BUNDLE_GEMFILE'] = File.expand_path("#{HOW_DEEP_WE_R_FROM_RAILS_ROOT}/Gemfile", File.dirname(__FILE__))
require 'bundler/setup'
pid_path = "#{RAILS_ROOT}/tmp/pids/unicorn.pid"
pid pid_path
# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
# documentation.
worker_processes 2 # SET ME!
# listen on both a Unix domain socket and a TCP port,
# we use a shorter backlog for quicker failover when busy
listen "#{SHARED_PATH}/sockets/unicorn.socket", :backlog => 1024 # SET ME!
# Preload our app for more speed
preload_app true
GC.respond_to?(:copy_on_write_friendly=) and
GC.copy_on_write_friendly = true
# nuke workers after 30 seconds instead of 60 seconds (the default)
timeout 60
# Help ensure your application will always spawn in the symlinked
# "current" directory that Capistrano sets up.
working_directory RAILS_ROOT
stderr_path "#{SHARED_PATH}/log/unicorn.stderr.log"
stdout_path "#{SHARED_PATH}/log/unicorn.stdout.log"
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
if defined?(ActiveRecord::Base)
ActiveRecord::Base.connection.disconnect!
end
# Before forking, kill the master process that belongs to the .oldbin PID.
# This enables 0 downtime deploys.
old_pid = pid_path + ".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|
# the following is *required* for Rails + "preload_app true",
if defined?(ActiveRecord::Base)
ActiveRecord::Base.establish_connection
end
# if preload_app is true, then you may also want to check and
# restart any other shared sockets/descriptors such as Memcached,
# and Redis. TokyoCabinet file handles are safe to reuse
# between any number of forked children (assuming your kernel
# correctly implements pread()/pwrite() system calls)
end
#!/bin/bash
### BEGIN INIT INFO
# Provides: unicorn
# Required-Start: $local_fs $remote_fs $network $syslog
# Required-Stop: $local_fs $remote_fs $network $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start the unicorns at boot
# Description: Enable Rails applications with unicorn at boot time.
### END INIT INFO
# This is /etc/init.d/unicorn (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/ganta
# based on modified version by http://github.com/zewelor
# which is based on:
# http://gist.github.com/2623205 by http://github.com/zewelor
# http://gist.github.com/504875 by http://github.com/jaygooby
# http://gist.github.com/308216 by http://github.com/mguterl
#
## A sample /etc/unicorn/my_app.conf
##
## RAILS_ENV=production
## RAILS_ROOT=/var/apps/www/my_app/current
## UNICORN="/opt/rbenv/shims/unicorn_rails"
## APP_USER="www-data"
#
# This configures a unicorn master for your app at /opt/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
RBENV_FILE_TO_SOURCE=/etc/profile.d/rbenv.sh
sig () {
test -s "$PID" && kill -$1 `cat "$PID"`
}
oldsig () {
test -s "$OLD_PID" && kill -$1 `cat "$OLD_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)
sig USR2 && sleep 5 && oldsig QUIT && echo "Killing old master" `cat $OLD_PID` && return 0
echo >&2 "Couldn't reload, starting '$CMD' instead"
eval $CMD
;;
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
export APP_NAME=`basename $1 .conf`
echo "Launching ${APP_NAME}"
if [ -z $APP_USER ]; then
if [ `getent passwd | awk -F: '{ print $1 }' | grep "^${APP_NAME}$" | wc -l` -eq 1 ]; then
export APP_USER=$APP_NAME
else
echo "The is no user defined in ${CONFIG}, and the is no user in the system called ${APP_NAME}"
return 1
fi
fi
if [ -z $RAILS_ROOT ]; then
if [ -d "/home/${APP_USER}/www/current" ]; then
export RAILS_ROOT="/home/${APP_USER}/www/current"
else
echo "Rails root is not defined in ${CONFIG}"
return 1
fi
fi
if [ -z $RAILS_ENV ]; then
export RAILS_ENV="production"
fi
# If unicorn binary was not defined in config
if [ -z $UNICORN ]; then
UNICORN="unicorn_rails"
fi
cd $RAILS_ROOT || return 1
export PID=$RAILS_ROOT/tmp/pids/unicorn.pid
export OLD_PID="$PID.oldbin"
CMD="sudo -u ${APP_USER} $(rbenv which $UNICORN) -E ${RAILS_ENV} -c ${RAILS_ROOT}/config/unicorn.rb -D"
return
}
# 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
source $RBENV_FILE_TO_SOURCE
if [ $2 ]; then
. /etc/unicorn/$2.conf
setup "/etc/unicorn/$2.conf"
if [ $? -eq 1 ]; then
exit 1
fi
cmd $1
else
for CONFIG in /etc/unicorn/*.conf; do
# clean variables from prev configs
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment