From 8af1a7640dbbead32f46d30d34f7bd032d4d01b1 Mon Sep 17 00:00:00 2001 From: hockeytim11 Date: Wed, 1 Feb 2017 08:51:40 -0700 Subject: [PATCH 1/6] Don't exit until child process exits To allow the service to exit cleanly, we need to only exit when the child does. --- lib/wrapper.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/wrapper.js b/lib/wrapper.js index 74a3608..48d20f0 100644 --- a/lib/wrapper.js +++ b/lib/wrapper.js @@ -169,6 +169,9 @@ var launch = function(){ console.error(argv.f+' exited with error code '+code); process.exit(); server.unref(); + } else if (forcekill) { + process.exit(); + server.unref(); } delete child.pid; @@ -183,7 +186,6 @@ process.on('exit',function(){ console.log("Got exit signal, closing down"); forcekill = true; child.kill(); - process.exit(); }); // Killing the wrapper does not kill the child node process without this handler @@ -191,7 +193,6 @@ process.on('SIGTERM',function(){ console.log("Got SIGTERM, closing down"); forcekill = true; child.kill(); - process.exit(); }); process.on('uncaughtException', function(err) { From 16bdeefe12d6a3bec922430b1f6191e48b0c7e45 Mon Sep 17 00:00:00 2001 From: hockeytim11 Date: Fri, 10 Feb 2017 11:11:28 -0700 Subject: [PATCH 2/6] Adding clean shutdown support for systemd --- lib/daemon.js | 23 +++++++++++++++++++++++ lib/systemd.js | 2 ++ lib/templates/systemd/service | 6 ++++++ 3 files changed, 31 insertions(+) diff --git a/lib/daemon.js b/lib/daemon.js index 7844257..20152a7 100644 --- a/lib/daemon.js +++ b/lib/daemon.js @@ -96,6 +96,29 @@ var daemon = function(config) { configurable: false, value: config.group || 'root' }, + + /** + * @cfg {Boolean} [stopparentfirst=false] + * Allow the service to shutdown cleanly. + */ + stopparentfirst: { + enumerable: true, + writable: false, + configurable: false, + value: config.stopparentfirst + }, + + /** + * @cfg {Number} [stoptimeout=30] + * How long to wait in seconds before force killing the application. + * This only takes effect when stopparentfirst is enabled. + */ + stoptimeout: { + enumerable: true, + writable: false, + configurable: false, + value: config.stoptimeout || 30 + }, system: { enumerable: false, diff --git a/lib/systemd.js b/lib/systemd.js index e194518..2e0430b 100644 --- a/lib/systemd.js +++ b/lib/systemd.js @@ -138,6 +138,8 @@ var init = function(config){ env: '', created: new Date(), execpath: process.execPath, + stopparentfirst: config.stopparentfirst, + stoptimeout: config.stoptimeout }; var _env = []; diff --git a/lib/templates/systemd/service b/lib/templates/systemd/service index 270df83..7e2dbd5 100644 --- a/lib/templates/systemd/service +++ b/lib/templates/systemd/service @@ -8,6 +8,12 @@ SyslogIdentifier={{label}} User={{user}} Group={{group}} Environment={{env}} +{{#stopparentfirst}} +KillMode=process +{{/stopparentfirst}} +{{#stoptimeout}} +TimeoutStopSec={{stoptimeout}} +{{/stoptimeout}} [Install] WantedBy=multi-user.target From 0e0d7e34d82a2de907c6d1a10047eccd9df8e76a Mon Sep 17 00:00:00 2001 From: hockeytim11 Date: Fri, 10 Feb 2017 13:38:11 -0700 Subject: [PATCH 3/6] adding a line to poll until the process exits This is where we could add a timeout. Poll until we reach the timeout, then force kill. --- lib/templates/systemv/redhat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/templates/systemv/redhat b/lib/templates/systemv/redhat index e0ee014..52cb700 100644 --- a/lib/templates/systemv/redhat +++ b/lib/templates/systemv/redhat @@ -36,6 +36,8 @@ do_stop() echo -n "Stopping $LABEL:" PID=`cat ${PIDFILE}` kill $PID > /dev/null + # wait for process to exit + while kill -0 $PID 2>/dev/null; do sleep 1;done; if [ -f ${LOCK_FILE} ] ; then rm ${LOCK_FILE} fi From 5026028040f566f293f9ac7913bdc66861c5b339 Mon Sep 17 00:00:00 2001 From: hockeytim11 Date: Fri, 10 Feb 2017 21:57:54 -0700 Subject: [PATCH 4/6] Adding stoptimeout to debian script stoptimeout is now exposed as a parameter --- lib/templates/systemv/debian | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/templates/systemv/debian b/lib/templates/systemv/debian index 5e103b7..04d0ed2 100644 --- a/lib/templates/systemv/debian +++ b/lib/templates/systemv/debian @@ -66,6 +66,7 @@ INIT_SCRIPT_NAME=`basename $THIS_ARG` INIT_SCRIPT_NAME_NOEXT=${INIT_SCRIPT_NAME%.*} PIDFILE="$LOCAL_VAR_RUN/$INIT_SCRIPT_NAME_NOEXT.pid" SCRIPTNAME=/etc/init.d/$INIT_SCRIPT_NAME +STOPTIMEOUT={{stoptimeout}} # Exit if the package is not installed [ -x "$DAEMON" ] || { echo "can't find Node.js ($DAEMON)" >&2; exit 0; } @@ -147,7 +148,7 @@ do_stop() # 2 if daemon could not be stopped # other if a failure occurred - start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --chuid $NODEUSER --name $LABEL + start-stop-daemon --stop --quiet --retry=TERM/$STOPTIMEOUT/KILL/5 --pidfile $PIDFILE --chuid $NODEUSER --name $LABEL RETVAL="$?" #[ "$VERBOSE" != no ] && [ "$RETVAL" = 1 ] && log_daemon_msg " ---> SIGKILL failed => hardkill $DESC" "$INIT_SCRIPT_NAME_NOEXT" From 8cef6faa4f70911a360dfb005698ccb5923760c3 Mon Sep 17 00:00:00 2001 From: hockeytim11 Date: Sat, 11 Feb 2017 10:02:26 -0700 Subject: [PATCH 5/6] adding stoptimeout to redhat Adding a countdown before sending a SIGKILL --- lib/systemv.js | 1 + lib/templates/systemv/redhat | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/systemv.js b/lib/systemv.js index 8cbbe51..7535b0c 100644 --- a/lib/systemv.js +++ b/lib/systemv.js @@ -167,6 +167,7 @@ var init = function(config){ env: '', created: new Date(), execpath: process.execPath, + stoptimeout: config.stoptimeout }; // escape the double quotes in the wrappercode args here if we are on a redhat system diff --git a/lib/templates/systemv/redhat b/lib/templates/systemv/redhat index 52cb700..29da9e0 100644 --- a/lib/templates/systemv/redhat +++ b/lib/templates/systemv/redhat @@ -36,8 +36,16 @@ do_stop() echo -n "Stopping $LABEL:" PID=`cat ${PIDFILE}` kill $PID > /dev/null + TIMEOUT={{stoptimeout}} # wait for process to exit - while kill -0 $PID 2>/dev/null; do sleep 1;done; + # if waiting longer than the timeout send a SIGKILL + while kill -0 $PID 2>/dev/null; do + if [ $TIMEOUT -lte 0 ]; then + kill -9 $PID + fi + sleep 1; + ((TIMEOUT--)); + done; if [ -f ${LOCK_FILE} ] ; then rm ${LOCK_FILE} fi From 22ce117b7c80de8717791ad4337dcb3cf437822e Mon Sep 17 00:00:00 2001 From: hockeytim11 Date: Sat, 11 Feb 2017 10:27:56 -0700 Subject: [PATCH 6/6] fixing if test and adding a message if the timeout is reached --- lib/templates/systemv/redhat | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/templates/systemv/redhat b/lib/templates/systemv/redhat index 29da9e0..55044b8 100644 --- a/lib/templates/systemv/redhat +++ b/lib/templates/systemv/redhat @@ -40,8 +40,9 @@ do_stop() # wait for process to exit # if waiting longer than the timeout send a SIGKILL while kill -0 $PID 2>/dev/null; do - if [ $TIMEOUT -lte 0 ]; then + if [ $TIMEOUT -le 0 ]; then kill -9 $PID + echo "Process didn't exit before timeout, sent SIGKILL" fi sleep 1; ((TIMEOUT--));