11#! /bin/sh
22# /usr/local/pdsm/services-available/dash-node
3- # Simple PDSM service wrapper for IIAB-oA Dashboard (Node.js)
3+ # PDSM service wrapper for the IIAB-oA Dashboard (Node.js).
4+ # ADFA-4839: run the COMPILED JS (dist/server.js) instead of `ts-node server.ts`,
5+ # with a small respawn supervisor and a health probe.
46
57PDSM_COMMON=" /usr/local/pdsm/lib/pdsm-common.sh"
68[ -r " $PDSM_COMMON " ] && . " $PDSM_COMMON "
79
810SERVICE_NAME=" dash-node"
9-
1011APP_DIR=" /library/dashboard"
11- # Feature detection: we use npx by default, but if not we rely on
12- # yarn as engine (currently @32 bits)
13- if command -v npx > /dev/null 2>&1 ; then
14- APP_CMD=" npx ts-node server.ts"
15- else
16- APP_CMD=" yarn run ts-node server.ts"
17- fi
12+ ENTRY=" dist/server.js"
1813LOGFILE=" /var/log/dash-node.log"
14+ SUP_PIDFILE=" /var/run/dash-node.sup.pid"
1915
2016running () {
21- # Look directly for the actual process name, ignoring the PID file
22- pgrep -f " ts- node server.ts " > /dev/null 2>&1
17+ # Match the actual server process, not the supervisor shell.
18+ pgrep -f " node $ENTRY " > /dev/null 2>&1
2319}
2420
2521start () {
@@ -30,9 +26,16 @@ start() {
3026
3127 echo " [pdsm:$SERVICE_NAME ] starting..."
3228 cd " $APP_DIR " || return 1
33- nohup $APP_CMD > " $LOGFILE " 2>&1 &
3429
35- for i in $( seq 1 " ${PDSM_START_TIMEOUT:- 5} " ) ; do
30+ # Supervisor: respawn the server if it exits. Its PID is recorded so stop() can end
31+ # the respawn loop before killing the server. ENTRY/LOGFILE are passed via the env so
32+ # the inner shell expands them at runtime (avoids brittle nested quoting).
33+ ENTRY=" $ENTRY " LOGFILE=" $LOGFILE " nohup sh -c \
34+ ' while :; do node "$ENTRY" >> "$LOGFILE" 2>&1; echo "[dash-node] exited ($?); respawning in 2s" >> "$LOGFILE"; sleep 2; done' \
35+ > /dev/null 2>&1 &
36+ echo $! > " $SUP_PIDFILE "
37+
38+ for i in $( seq 1 " ${PDSM_START_TIMEOUT:- 8} " ) ; do
3639 if running; then
3740 echo " [pdsm:$SERVICE_NAME ] started"
3841 return 0
@@ -45,14 +48,19 @@ start() {
4548}
4649
4750stop () {
51+ # Kill the supervisor first so it stops respawning, then the server itself.
52+ if [ -f " $SUP_PIDFILE " ]; then
53+ kill " $( cat " $SUP_PIDFILE " ) " 2> /dev/null || true
54+ rm -f " $SUP_PIDFILE "
55+ fi
56+
4857 if ! running; then
4958 echo " [pdsm:$SERVICE_NAME ] already stopped"
5059 return 0
5160 fi
5261
5362 echo " [pdsm:$SERVICE_NAME ] stopping..."
54- # Terminate by name
55- pkill -f " ts-node server.ts" 2> /dev/null || true
63+ pkill -f " node $ENTRY " 2> /dev/null || true
5664
5765 for i in $( seq 1 " ${PDSM_START_TIMEOUT:- 5} " ) ; do
5866 if ! running; then
@@ -62,24 +70,33 @@ stop() {
6270 sleep 1
6371 done
6472
65- # Force kill if it resists
66- pkill -9 -f " ts-node server.ts" 2> /dev/null || true
73+ pkill -9 -f " node $ENTRY " 2> /dev/null || true
6774 echo " [pdsm:$SERVICE_NAME ] forced stop"
6875 return 1
6976}
7077
7178status () {
7279 if running; then
73- real_pid=$( pgrep -f " ts-node server.ts" | head -n 1)
74- echo " [pdsm:$SERVICE_NAME ] running (PID: $real_pid )"
80+ echo " [pdsm:$SERVICE_NAME ] running (PID: $( pgrep -f " node $ENTRY " | head -n 1) )"
7581 return 0
7682 fi
7783 echo " [pdsm:$SERVICE_NAME ] not running"
7884 return 3
7985}
8086
87+ health () {
88+ # Liveness: the REST API answers 2xx on loopback (the jobs list is always 200).
89+ if command -v curl > /dev/null 2>&1 && \
90+ curl -fs -o /dev/null " http://127.0.0.1:4000/api/kiwix/jobs" ; then
91+ echo " [pdsm:$SERVICE_NAME ] healthy"
92+ return 0
93+ fi
94+ echo " [pdsm:$SERVICE_NAME ] unhealthy"
95+ return 1
96+ }
97+
8198case " $1 " in
82- start|stop|status) " $1 " ;;
99+ start|stop|status|health ) " $1 " ;;
83100 restart) stop; start ;;
84- * ) echo " Usage: $0 {start|stop|restart|status}" >&2 ; exit 1 ;;
101+ * ) echo " Usage: $0 {start|stop|restart|status|health }" >&2 ; exit 1 ;;
85102esac
0 commit comments