Skip to content

Instantly share code, notes, and snippets.

@allaryin
Forked from killercup/README.md
Last active January 4, 2017 20:01
Show Gist options
  • Save allaryin/e6ebf5f19934e44040b60dbefb930c3f to your computer and use it in GitHub Desktop.
Save allaryin/e6ebf5f19934e44040b60dbefb930c3f to your computer and use it in GitHub Desktop.
Unicorn, init.d - native ruby, no rvm/rbenv/etc...

This is my take of the init script system I've seen tossed around. Because I don't run RVM on servers, I have removed it in favor of assuming the user can define the correct path to unicorn themselves. If you need RVM, see the upstream version of this gist.

Installation

  1. Have a server with 1+ working unicorn instances with config defined in config/unicorn.rb.
  2. Create /etc/unicorn/[APPNAME].conf for each app on the server.
  3. Install init script at /etc/init.d/unicorn.
  4. sudo update-rc.d unicorn defaults

Bugfixes

There were a lot of issues with the previous versions of this script, mostly related to the fact that it simply did not work in a modern environment.

  • Setting -e -u and then deliberately testing for the existence of unset variables is guaranteed to fail... Like the script would never run in the most basic of use cases.
  • The restart logic was broken and would always log an error, regardless of the way it ran.
  • Telling users to set a variable in config, but then hard overwriting in the script it is just annoying...
# This is the actual config for your app
# Save this to /etc/unicorn/<APPNAME>.conf
# My configs look like this:
RAILS_ROOT=/var/www/<APPNAME>/current/
RAILS_ENV=production
UNICORN="bundle exec unicorn"
#!/bin/sh
### 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 (without _init.sh) init.d script for single
# or multiple unicorn installations. Expects at least one .conf file in
# /etc/unicorn
#
# Modified by allaryin [2017.01.04] - https://gist.github.com/allaryin/e6ebf5f19934e44040b60dbefb930c3f
# based on modified version by http://github.com/killercup
# based on modified version by [email protected] 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
##
## RAILS_ENV=production
## RAILS_ROOT=/var/apps/www/my_app/current
## UNICORN="/usr/local/rvm/bin/<WRAPPED_NAME>"
#
# 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
ARGS="$1 $2"
#set -x
set -e
set -u
DEF_RAILS_ENV=production
DEF_AS_USER=deploy
DEF_UNICORN="bundle exec unicorn"
sig () {
test -s "$PID" && kill -$1 `cat "$PID"`
}
oldsig () {
test -s "$OLD_PID" && kill -$1 `cat "$OLD_PID"`
}
run () {
if [ "$(id -un)" = "$AS_USER" ]; then
eval $*
else
su -c "cd `pwd`; $*" - $AS_USER
fi
}
cmd () {
case $1 in
start)
sig 0 && echo >&2 "Already running" && exit 0
run $CMD
echo "Starting"
;;
stop)
sig QUIT && echo "Stopping" && exit 0
echo >&2 "Not running"
;;
force-stop)
sig TERM && echo "Forcing a stop" && exit 0
echo >&2 "Not running"
;;
restart|reload)
set +e
sig USR2
if [ $? -eq 0 ]; then
sleep 5 && oldsig 0
if [ $? -eq 0 ]; then
echo "Killing old master" `cat $OLD_PID`
oldsig QUIT
set -e
else
exit 0
fi
fi
echo >&2 "Couldn't reload, starting '$CMD' instead"
run $CMD
;;
upgrade)
sig USR2 && echo Upgraded && exit 0
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
run $CMD
;;
rotate)
sig USR1 && echo rotated logs OK && exit 0
echo >&2 "Couldn't rotate logs" && exit 1
;;
*)
echo >&2 "Usage: $0 <start|stop|restart|upgrade|rotate|force-stop>"
exit 1
;;
esac
}
setup () {
echo "$RAILS_ROOT: "
cd $RAILS_ROOT || exit 1
export PID=$RAILS_ROOT/tmp/pids/unicorn.pid
export OLD_PID="$PID.oldbin"
if [ -z "${RAILS_ENV}" ]; then
RAILS_ENV=${DEF_RAILS_ENV}
fi
export RAILS_ENV
if [ -z "${AS_USER}" ]; then
export AS_USER=${DEF_AS_USER}
fi
if [ -z "${UNICORN}" ]; then
UNICORN="${DEF_UNICORN}"
fi
CMD="$UNICORN -E ${RAILS_ENV} -c ${RAILS_ROOT}/config/unicorn.rb -D"
}
start_stop () {
# 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 [ "$#" -eq 2 ]; then
. /etc/unicorn/$2.conf
setup
cmd $1
else
for CONFIG in /etc/unicorn/*.conf; do
# import the variables
. $CONFIG
setup
# run the start/stop/etc command
cmd $1
done
fi
}
start_stop $ARGS
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment