about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2016-07-07 01:06:45 +0000
committerEric Wong <e@80x24.org>2016-07-07 01:13:54 +0000
commit84989a48f20d1bc383a9925b919edc66fc4bccdb (patch)
tree365cdf35b369a67f3139f1aa15f12b4b8f558373
parent97ef2a9c592fbdb756aa6a73e2e6c90b6b3cda18 (diff)
downloadyahns-84989a48f20d1bc383a9925b919edc66fc4bccdb.tar.gz
Reduce raciness in the init script and add LSB tags.
However, the systemd examples should be race-free and
safer (if one feels safe using systemd :P)
-rw-r--r--examples/init.sh43
-rw-r--r--examples/logrotate.conf5
-rw-r--r--examples/yahns.socket17
-rw-r--r--examples/yahns@.service50
4 files changed, 106 insertions, 9 deletions
diff --git a/examples/init.sh b/examples/init.sh
index 9464220..6fe1ae6 100644
--- a/examples/init.sh
+++ b/examples/init.sh
@@ -2,8 +2,14 @@
 # To the extent possible under law, Eric Wong has waived all copyright and
 # related or neighboring rights to this examples
 set -e
-# Example init script, this can be used with nginx, too,
-# since nginx and yahns accept the same signals
+### BEGIN INIT INFO
+# Provides:          yahns
+# Required-Start:    $local_fs $network
+# Required-Stop:     $local_fs $network
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start/stop yahns Ruby app server
+### END INIT INFO
 
 # Feel free to change any of the following variables for your app:
 TIMEOUT=${TIMEOUT-60}
@@ -11,21 +17,22 @@ APP_ROOT=/home/x/my_app/current
 PID=$APP_ROOT/tmp/pids/yahns.pid
 CMD="/usr/bin/yahns -D -c $APP_ROOT/config/yahns.rb"
 INIT_CONF=$APP_ROOT/config/init.conf
+UPGRADE_DELAY=${UPGRADE_DELAY-2}
 action="$1"
 set -u
 
 test -f "$INIT_CONF" && . $INIT_CONF
 
-old_pid="$PID.oldbin"
+OLD="$PID.oldbin"
 
 cd $APP_ROOT || exit 1
 
 sig () {
-        test -s "$PID" && kill -$1 `cat $PID`
+        test -s "$PID" && kill -$1 $(cat $PID)
 }
 
 oldsig () {
-        test -s $old_pid && kill -$1 `cat $old_pid`
+        test -s "$OLD" && kill -$1 $(cat $OLD)
 }
 
 case $action in
@@ -47,18 +54,36 @@ restart|reload)
         $CMD
         ;;
 upgrade)
-        if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
+        if oldsig 0
+        then
+                echo >&2 "Old upgraded process still running with $OLD"
+                exit 1
+        fi
+
+        cur_pid=
+        if test -s "$PID"
+        then
+                cur_pid=$(cat $PID)
+        fi
+
+        if test -n "$cur_pid" &&
+                        kill -USR2 "$cur_pid" &&
+                        sleep $UPGRADE_DELAY &&
+                        new_pid=$(cat $PID) &&
+                        test x"$new_pid" != x"$cur_pid" &&
+                        kill -0 "$new_pid" &&
+                        kill -QUIT "$cur_pid"
         then
                 n=$TIMEOUT
-                while test -s $old_pid && test $n -ge 0
+                while kill -0 "$cur_pid" 2>/dev/null && test $n -ge 0
                 do
                         printf '.' && sleep 1 && n=$(( $n - 1 ))
                 done
                 echo
 
-                if test $n -lt 0 && test -s $old_pid
+                if test $n -lt 0 && kill -0 "$cur_pid" 2>/dev/null
                 then
-                        echo >&2 "$old_pid still exists after $TIMEOUT seconds"
+                        echo >&2 "$cur_pid still running after $TIMEOUT seconds"
                         exit 1
                 fi
                 exit 0
diff --git a/examples/logrotate.conf b/examples/logrotate.conf
index ebc92a5..b0d1351 100644
--- a/examples/logrotate.conf
+++ b/examples/logrotate.conf
@@ -25,6 +25,11 @@
         # config.  yahns supports the USR1 signal and we send it
         # as our "lastaction" action:
         lastaction
+                # systemd users do not have PID files,
+                # only signal the @1 process since the @2 is short-lived
+                # and only runs while @1 is restarting.
+                systemctl kill -s SIGUSR1 yahns@1.service
+
                 # assuming your pid file is in /var/run/yahns_app/pid
                 pid=/var/run/yahns_app/pid
                 test -s $pid && kill -USR1 "$(cat $pid)"
diff --git a/examples/yahns.socket b/examples/yahns.socket
new file mode 100644
index 0000000..6455b41
--- /dev/null
+++ b/examples/yahns.socket
@@ -0,0 +1,17 @@
+# ==> /etc/systemd/system/yahns.socket <==
+[Unit]
+Description = yahns sockets
+
+[Socket]
+
+# yahns can handle an arbitrary number of listen sockets,
+# so I prefer to keep listeners for IPv4 and IPv6 separate
+# to avoid ugly IPv4-mapped-IPv6 addresses for IPv4 clients:
+# (e.g ":ffff:10.0.0.1" instead of just "10.0.0.1").
+ListenStream = 0.0.0.0:443
+BindIPv6Only = ipv6-only
+ListenStream = [::]:443
+Service = yahns@1.service
+
+[Install]
+WantedBy = sockets.target
diff --git a/examples/yahns@.service b/examples/yahns@.service
new file mode 100644
index 0000000..1ee010f
--- /dev/null
+++ b/examples/yahns@.service
@@ -0,0 +1,50 @@
+# ==> /etc/systemd/system/yahns@.service <==
+# Since SIGUSR2 upgrades do not work under systemd, this service
+# file allows starting two (or more) simultaneous services
+# during upgrade (e.g. yahns@1 and yahns@2) with the intention
+# that they are both running during the upgrade process.
+#
+# This allows upgrading without downtime, using yahns@2 as a
+# temporary hot spare:
+#
+#   systemctl start yahns@2
+#   sleep 2 # wait for yahns@2 to boot, increase as necessary for big apps
+#   systemctl restart yahns@1
+#   sleep 2 # wait for yahns@1 to warmup
+#   systemctl stop yahns@2
+
+[Unit]
+Description = yahns Ruby server %i
+Wants = yahns.socket
+After = yahns.socket
+
+[Service]
+# yahns can handle lots of open files:
+LimitNOFILE = 32768
+LimitCORE = infinity
+
+# The listen socket we give yahns should be blocking for optimal
+# load distribution between processes under the Linux kernel.
+# NonBlocking is false by default in systemd, but we specify it
+# here anyways to discourage users from blindly changing it.
+Sockets = yahns.socket
+NonBlocking = false
+
+# bundler users must use the "--keep-file-descriptors" switch, here:
+# ExecStart = /path/to/bin/bundle exec --keep-file-descriptors yahns -c ...
+ExecStart = /path/to/bin/yahns -c /path/to/yahns.conf.rb
+KillSignal = SIGQUIT
+User = www-data
+Group = www-data
+ExecReload = /bin/kill -HUP $MAINPID
+
+# this should match the shutdown_timeout value in yahns_config(5)
+TimeoutStopSec = 600
+
+# Only kill the master process, it may be harmful to signal
+# workers via default "control-group" setting since some
+# Ruby extensions and applications misbehave on interrupts
+KillMode = process
+
+[Install]
+WantedBy = multi-user.target