В процессе работы над проектом с использованием Node.js в качестве серверсайда, возникла задача запуска JS скрипта в качестве сервиса, со всем плюшками типа start, stop, restart. По этой теме в принципе уже достаточно информации, но она в основном сводится к использованию Monit + Init под линуксом, либо кратких советов типа «use nodemon, Luke».
В моём случае в качестве продакшн-сервера была машина на FreeBSD. В качестве утилиты запускающей JS файл как процесс мне приглянулся forever. Эта штука, в отличии от nodemon, умеет следить за запущенными под ней процессами и поднимать их при падении без ожидания изменения в исходниках скрипта, что очень удобно именно на продакшене. К тому же forever умеет показывать текущий список запущеных процессов, с отображением их аптайма, ну и позволяет останавливать/перезапускать процессы по имени или индексу.
Недолго думая, был написан rc.d скрипт:
# cat /usr/local/etc/rc.d/factory
В /etc/rc.conf была добавлена строка: factory_enable=«YES». После чего произведён пробный запуск: /usr/local/etc/rc.d/factory start и скрипт радостно запустился. Проверив так же работу restart и stop я довольный собой отправился налить себе чаю. При этом, дабы проверить запуск скрипта в боевых условиях, отправил в ребут сервер.
Вернувшись с чаем, я открыл браузер и обнаружил что серверсайд не запустился. Журнал forever содержал следующее:
Таким образом, с момента как сервис «запустился», дочерний JS-процесс успел упасть/подняться уже 11124 раза, пока я топил в кипятке пакетик с чаем.
Всякий раз, когда что-то запускается с консоли но не работает при старте в «чистом» окружении внутренний голос шепчет одно и то же: «Переменные окружения же!». Но как же так? Я же указал HOME о котором везде пишут, и NODE_ENV=production необходимый для работы express. Что ещё надо?
А надо сравнить разницу между пользовательским окружением и окружением при старте системы. В результате этого сравнения в rc.d скрипт, в секцию «start», было добавлено ещё три переменные окружения: USER, PATH и PWD. После этого JS-скрипт начал стартовать корректно. Собственно рабочая версия rc.d скрипта стала выглядеть так:
Покопавшись в «этих ваших интернетах», был удивлён отсутствию информации об отказоустойчивом запуске node.js сервиса таким способом на машине под FreeBSD. Собственно о чём и решил написать, вдруг будет кому полезно.
В моём случае в качестве продакшн-сервера была машина на FreeBSD. В качестве утилиты запускающей JS файл как процесс мне приглянулся forever. Эта штука, в отличии от nodemon, умеет следить за запущенными под ней процессами и поднимать их при падении без ожидания изменения в исходниках скрипта, что очень удобно именно на продакшене. К тому же forever умеет показывать текущий список запущеных процессов, с отображением их аптайма, ну и позволяет останавливать/перезапускать процессы по имени или индексу.
Недолго думая, был написан rc.d скрипт:
# cat /usr/local/etc/rc.d/factory
#!/bin/sh # PROVIDE: factory # REQUIRE: NETWORKING SERVERS DAEMON # BEFORE: LOGIN # KEYWORD: shutdown . /etc/rc.subr name="factory" forever="/usr/local/bin/node /usr/local/bin/forever" workdir="/usr/home/www/factory" script="index.js" rcvar=`set_rcvar` start_cmd="start" stop_cmd="stop" restart_cmd="restart" load_rc_config $name eval "${rcvar}=\${${rcvar}:-'NO'}" start() { HOME=/root NODE_ENV=production ${forever} start -a -l /var/log/forever.log -o /dev/null -e ${workdir}/logs/node_err.log --sourceDir ${workdir} ${workdir}/node/${script} } stop() { ${forever} stop ${workdir}/node/${script} } restart() { ${forever} restart ${workdir}/node/${script} } run_rc_command "$1"
В /etc/rc.conf была добавлена строка: factory_enable=«YES». После чего произведён пробный запуск: /usr/local/etc/rc.d/factory start и скрипт радостно запустился. Проверив так же работу restart и stop я довольный собой отправился налить себе чаю. При этом, дабы проверить запуск скрипта в боевых условиях, отправил в ребут сервер.
Вернувшись с чаем, я открыл браузер и обнаружил что серверсайд не запустился. Журнал forever содержал следующее:
# cat /var/log/forever.log ... warn: Forever restarting script for 11119 time warn: Forever detected script exited with code: 127 warn: Forever restarting script for 11120 time warn: Forever detected script exited with code: 127 warn: Forever restarting script for 11121 time warn: Forever detected script exited with code: 127 warn: Forever restarting script for 11122 time warn: Forever detected script exited with code: 127 warn: Forever restarting script for 11123 time warn: Forever detected script exited with code: 127 warn: Forever restarting script for 11124 time
Таким образом, с момента как сервис «запустился», дочерний JS-процесс успел упасть/подняться уже 11124 раза, пока я топил в кипятке пакетик с чаем.
Всякий раз, когда что-то запускается с консоли но не работает при старте в «чистом» окружении внутренний голос шепчет одно и то же: «Переменные окружения же!». Но как же так? Я же указал HOME о котором везде пишут, и NODE_ENV=production необходимый для работы express. Что ещё надо?
А надо сравнить разницу между пользовательским окружением и окружением при старте системы. В результате этого сравнения в rc.d скрипт, в секцию «start», было добавлено ещё три переменные окружения: USER, PATH и PWD. После этого JS-скрипт начал стартовать корректно. Собственно рабочая версия rc.d скрипта стала выглядеть так:
#!/bin/sh # PROVIDE: factory # REQUIRE: NETWORKING SERVERS DAEMON # BEFORE: LOGIN # KEYWORD: shutdown . /etc/rc.subr name="factory" forever="/usr/local/bin/node /usr/local/bin/forever" workdir="/usr/home/www/factory" script="index.js" rcvar=`set_rcvar` start_cmd="start" stop_cmd="stop" restart_cmd="restart" load_rc_config $name eval "${rcvar}=\${${rcvar}:-'NO'}" start() { USER=root PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin PWD=/root HOME=/root NODE_ENV=production ${forever} start -a -l /var/log/forever.log -o /dev/null -e ${workdir}/logs/node_err.log --sourceDir ${workdir} ${workdir}/node/${script} } stop() { ${forever} stop ${workdir}/node/${script} } restart() { ${forever} restart ${workdir}/node/${script} } run_rc_command "$1"
Покопавшись в «этих ваших интернетах», был удивлён отсутствию информации об отказоустойчивом запуске node.js сервиса таким способом на машине под FreeBSD. Собственно о чём и решил написать, вдруг будет кому полезно.
