#!/bin/bash ### BEGIN INIT INFO # Provides: {{ item.service }} # Required-Start: $network $remote_fs $local_fs # Required-Stop: $network $remote_fs $local_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: forever-service startup script for {{ item.service }} # Description: forever-service startup script for node script based service {{ item.service }}, uses forever to start the service ### END INIT INFO # CLI {{ item.script|default('app.js') }} # Working Directory {{ item.cwd }} #this is to ensure forever is able to find out the correct root every time export FOREVER_ROOT="/root/.forever" FOREVER=$(which forever) PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" #Setup Environment variables (if any) {% for export in item.envVarsArray|default([]) %} export {{ export.key }}={{ export.value }} {% endfor %} # Check if any of $pid (could be plural) are running LOGFILE="/var/log/nodejs/{{ item.service }}.log" LOCKFILE="/var/lock/{{ item.service }}" # introduce some gaps between restarts and throttle continous restarts MIN_UPTIME="{{ item.minUptime|default('5000') }}" SPIN_SLEEP_TIME="{{ item.spinSleepTime|default('2000') }}" NODE_BIN_DIR="/usr/bin" NODE_PATH="/usr/lib/node_modules" # Add node to the path for situations in which the environment is passed. PATH=$NODE_BIN_DIR:$PATH export PATH=$PATH # Export all environment variables that must be visible for the Node.js # application process forked by Forever. It will not see any of the other # variables defined in this script. export NODE_PATH=$NODE_PATH # kill signal: Since default needs to be SIGTERM, it is important that services gracefully shutdown, # specially if they are doing transactions or other work which should not be interuppted in between # for exceptional situation where you dont care about abrupt shutdown, SIGKILL should be used KILL_SIGNAL="{{ item.killSignal|default('SIGTERM') }}" # Wait time afer with SIGKILL will be sent to the process, in case SIGTERM is not fully finished # This is required since when we use SIGTERM, some times if there is problem in code, it might take lot of time for process to exit # or process may never exit, in such siutation we have to forcebly kill it so that shutdown or service restart can be done appropriately # this wait time is in millisecond KILLWAITTIME={{ item.forceKillWaitTime|default('5000') }} killtree() { local _pid=$1 local _sig=${2:--TERM} kill -stop ${_pid} # needed to stop quickly forking parent from producing children between child killing and parent killing for _child in $(ps -o pid --no-headers --ppid ${_pid}); do killtree ${_child} ${_sig} done kill -${_sig} ${_pid} } checkpidexists() { [ -d "/proc/$1" ] && return 0 return 1 } start() { STATUS=$($FOREVER --plain list | sed 's/data:\(\s*\[[0-9]*\]\s*\({{ item.service }}\)\s.*\)/\2-status:\1/;tx;d;:x') if ! [ -z "$STATUS" ]; then echo "Service {{ item.service }} already running" return 0 fi echo "Starting {{ item.service }}" # move to the directory from where the inital forever script was launched so that even if it is relative it works as expected cd {{ item.cwd }} {% if item.applyUlimits|default(false) %} ulimit -f unlimited ulimit -t unlimited ulimit -v unlimited ulimit -n 64000 ulimit -m unlimited ulimit -u 32000 {% endif %} $FOREVER \ -a \ -l $LOGFILE \ --minUptime $MIN_UPTIME \ --spinSleepTime $SPIN_SLEEP_TIME \ --killSignal $KILL_SIGNAL \ {{ item.foreverOptions|default('') }} \ --uid {{ item.service }} \ --workingDir {{ item.cwd }} \ start {{ item.script|default('app.js') }} {{ item.scriptOptions|default('') }} 2>&1 >/dev/null RETVAL=$? [ $RETVAL = 0 ] && touch $LOCKFILE return $RETVAL } stop() { echo -n "Shutting down {{ item.service }}: " STATUS=$($FOREVER --plain list | sed 's/data:\(\s*\[[0-9]*\]\s*\({{ item.service }}\)\s.*\)/\2-status:\1/;tx;d;:x') if [ -z "$STATUS" ]; then echo "Not running" return 0 fi PID=$($FOREVER --plain list | sed -n -e '/data:\s*\[[0-9]*\]\s\({{ item.service }}\)\s/p' | awk '{print $7}') if [ -z "$PID" ]; then echo "Could not get pid" return 0 fi #run in background, since recent changes in forever, now blocks stop call with SIGTERM is finished #but we want to wait till some time and forcibly kill after elapsed time #without background script, we could be waiting forever $FOREVER stop {{ item.service }} 2>&1 >/dev/null & CURRENTWAITTIME=$KILLWAITTIME # wait for some time before forcefully killing the process while [ $CURRENTWAITTIME -gt 0 ]; do #check if the process is still running checkpidexists $PID if [ $? -ne 0 ]; then # if not running we can break, since no more wait is needed, service is stopped echo "Successful" break fi sleep 1 CURRENTWAITTIME=$(( $CURRENTWAITTIME - 1000)) done checkpidexists $PID if [ $? -eq 0 ]; then killtree $PID 9 echo 'Forced shutdown' fi rm -f $LOCKFILE 2>&1 >/dev/null return 0 } status() { STATUS=$($FOREVER --plain list | sed 's/data:\(\s*\[[0-9]*\]\s*\({{ item.service }}\)\s.*\)/\2-status:\1/;tx;d;:x') if [ -z "$STATUS" ]; then echo "{{ item.service }} is not running" RETVAL=3 else echo $STATUS RETVAL=0 fi return $RETVAL } case "$1" in start) start ;; stop) stop ;; status) status ;; restart) stop start ;; *) echo "Usage: {{ item.service }} {start|stop|status|restart}" exit 1 ;; esac exit $?