Newer
Older
#!/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"
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#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 $?