Forked from czarneckid/application-notes-zero-downtime-deploys-unicorn-nginx-runit-rvm-chef.md
Last active
March 7, 2017 14:25
-
-
Save JeanMertz/8996796 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# This file is managed by Chef, using the <%= node.name %> cookbook. | |
# Editing this file by hand is highly discouraged! | |
# | |
# Copyright (c) 2014 Jean Mertz <[email protected]> | |
# | |
# Permission is hereby granted, free of charge, to any person obtaining a copy | |
# of this software and associated documentation files (the "Software"), to deal | |
# in the Software without restriction, including without limitation the rights | |
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
# copies of the Software, and to permit persons to whom the Software is | |
# furnished to do so, subject to the following conditions: | |
# | |
# The above copyright notice and this permission notice shall be included in | |
# all copies or substantial portions of the Software. | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
# THE SOFTWARE. | |
# | |
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. | |
# | |
RUNIT_PID=$$ | |
APPLICATION_NAME=<%= @options[:app].application.name %> | |
APPLICATION_PATH=<%= File.join(@options[:app].path, 'current') %> | |
BUNDLE_CMD="<%= @options[:bundler] ? "#{@options[:bundle_command]} exec" : '' %>" | |
UNICORN_CMD=<%= @options[:smells_like_rack] ? 'unicorn' : 'unicorn_rails' %> | |
UNICORN_CONF=<%= File.join('/etc/unicorn', "#{@options[:app].application.name}.rb") %> | |
RAILS_ENV=<%= @options[:rails_env] %> | |
CUR_PID_FILE=<%= @options['pid'] %> | |
OLD_PID_FILE=$CUR_PID_FILE.oldbin | |
echo "Runit service restarted (PID: $RUNIT_PID)" | |
function is_unicorn_alive { | |
set +e | |
if [ -n $1 ] && kill -0 $1 >/dev/null 2>&1; then | |
echo "yes" | |
fi | |
set -e | |
} | |
if [ -e $OLD_PID_FILE ]; then | |
OLD_PID=$(cat $OLD_PID_FILE) | |
echo "Old master detected (PID: $OLD_PID), waiting for it to quit" | |
while [ -n "$(is_unicorn_alive $OLD_PID)" ]; do | |
sleep 5 | |
done | |
fi | |
if [ -e $CUR_PID_FILE ]; then | |
CUR_PID=$(cat $CUR_PID_FILE) | |
if [ -n "$(is_unicorn_alive $CUR_PID)" ]; then | |
echo "Detected running Unicorn instance (PID: $CUR_PID)" | |
RUNNING=true | |
fi | |
fi | |
function start { | |
unset ACTION | |
if [ $RUNNING ]; then | |
restart | |
else | |
echo 'Starting new unicorn instance' | |
cd $APPLICATION_PATH | |
$BUNDLE_CMD $UNICORN_CMD -c $UNICORN_CONF -E $RAILS_ENV -D | |
sleep 3 | |
CUR_PID=$(cat $CUR_PID_FILE) | |
fi | |
} | |
function stop { | |
unset ACTION | |
echo 'Initializing graceful shutdown' | |
kill -QUIT $CUR_PID | |
while [ -n "$(is_unicorn_alive $CUR_PID)" ]; do | |
echo '.' | |
sleep 2 | |
done | |
echo 'Unicorn stopped, exiting Runit process' | |
kill -9 $RUNIT_PID | |
} | |
function restart { | |
unset ACTION | |
echo "Restart request captured, swapping old master (PID: $CUR_PID) for new master with USR2" | |
kill -USR2 $CUR_PID | |
sleep 2 | |
echo 'Restarting Runit service to capture new master PID' | |
exit | |
} | |
function alarm { | |
unset ACTION | |
echo 'Unicorn process interrupted' | |
} | |
trap 'ACTION=stop' STOP TERM KILL | |
trap 'ACTION=restart' QUIT USR2 INT | |
trap 'ACTION=alarm' ALRM | |
[ $RUNNING ] || ACTION=start | |
if [ $ACTION ]; then | |
echo "Performing \"$ACTION\" action and going into sleep mode until new signal captured" | |
elif [ $RUNNING ]; then | |
echo "Going into sleep mode until new signal captured" | |
fi | |
if [ $ACTION ] || [ $RUNNING ]; then | |
while true; do | |
[ "$ACTION" == 'start' ] && start | |
[ "$ACTION" == 'stop' ] && stop | |
[ "$ACTION" == 'restart' ] && restart | |
[ "$ACTION" == 'alarm' ] && alarm | |
sleep 2 | |
done | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Perhaps I'm misunderstanding something, but at the moment if someone kills the actual unicorn master process, neither runit nor this wrapper script will realize that? If that's the case, I'd suggest to add another function call within the while loop to check every few seconds whether the pid mentioned in the pid file is valid. If not, just exit the script and let runit handle the situation by restarting the wrapper script.