Site icon Soul & Shell Blog

NodeJS Server to Linux Service Daemon 製作教學

NodeJS 不死行程linux-deamon

Linux 系統中的服務,通常都是以 Daemon 的形式存在,Daemon 泛指一種在背景執行的程序,通常可以長時間工作不會中斷。最近剛好要將一個 Node.JS 所設計的系統執行在 Linux 中,由於 Linux 在慣例上會把服務封裝為 Linux Service 並且將啟動器集中在 /etc/init.d 目錄中進行管理。能夠遵循 Linux 的慣例佈署系統是個好方法,免得換了一個人維護就得換顆腦袋。

談到 Node.JS 就頭大了,Node.JS 是單執行緒,當程式拋出例外錯誤而又沒有順利捕捉處理,就會造成程式中斷,服務也就同時中斷。今天順便介紹 forever 這個套件,顧名思義能讓您的 NodeJS 程序永恆地執行下去,安裝方式很簡單,如下:

# npm install forever -g

假設您的應用程式為 app.js,那麼安裝好 forever 之後就可以透過以下命令啟動:

$ forever start app.js

這樣當 app.js 錯誤中斷時,就會自動重新啟動,當然這個方法不是正解,能夠搭配其他方法監控服務會比較保險,像是 Log 與 Notification Email 等等機制。

Linux Service

接下來我們需要撰寫一支 Shell Script 來封裝 forever + Node.JS,這支 Script 需放置於 /etc/init.d 目錄中,這樣一來我們就可以統一透過以下 service 命命管理服務,假設檔名為 my-service,服務執行如下:

# service my-service start

# service my-service stop

# service my-service restart

# service my-service status

Script 內容如下 (GitHub),其中停用 Service 的方法,如果改用 forever stop 取代 kill 會更好:

#!/bin/sh

### BEGIN INIT INFO
# Provides:          
# Required-Start:    my-service
# Required-Stop:     my-service
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: My Linux Service
### END INIT INFO

set -e

SERVICE_NAME=`basename $0`
PIDFILE=/var/run/myserv.pid
LOGPATH="/var/log/${SERVICE_NAME}"
FOREVER_BIN=`which forever`
APP_PATH="/var/share/work-js/app.js"

case $1 in
	start)
		if [ -e "${PIDFILE}" ]; then
			PID=`cat ${PIDFILE}`
			echo "Service is running already. (PID=${PID})"
			exit 1
		fi
		if [ ! -d "${LOGPATH}" ]; then
			mkdir -p "${LOGPATH}"
		fi
		PID=`ps aux | grep ${APP_PATH} | head -n1 | awk '{print $2}'`
		${FOREVER_BIN} -a -l "${LOGPATH}/service.log" -o "${LOGPATH}/out.log" -e "${LOGPATH}/error.log" start ${APP_PATH} > "${LOGPATH}/start.log"
		rm -rf ${PIDFILE}
		echo "${PID}" > ${PIDFILE}
		echo "Service ${SERVICE_NAME} start. PID=${PID}"
		;;
	stop)
		if [ ! -e "${PIDFILE}" ]; then
			echo "Service is not running."
		else
			PID=`cat ${PIDFILE}`
			kill ${PID} || true
			rm -rf ${PIDFILE}
			echo "Service ${SERVICE_NAME} stop. PID=${PID}"
		fi
		;;
	restart)
		$0 stop
		sleep 1
		$0 start
		;;
	status)
		if [ -e "${PIDFILE}" ]; then
			PID=`cat ${PIDFILE}`
			echo "Service is running. (PID=${PID})"
		else
				echo "Service is not running."
		fi
		;;
	*)
		echo "Usage: ${0} {start|stop|restart|status}"
		exit 1
		;;
esac

參考資料

Exit mobile version