Node.js daemon for FreeBSD: forever + rc.d

In the process of working on a project using Node.js as a server side, the problem arose of launching a JS script as a service, with all the goodies like start, stop, restart. On this topic, in principle, there is already enough information, but it basically boils down to using Monit + Init under Linux, or short tips like “use nodemon, Luke”.

In my case, there was a machine on FreeBSD as the production server. As a utility launching a JS file as a process, I liked forever. This thing, unlike nodemon, can monitor the processes running under it and raise them when it crashes without waiting for a change in the script source, which is very convenient on production. In addition, forever can show the current list of running processes, with the display of their uptime, well, and allows you to stop / restart processes by name or index.

Without thinking twice, the rc.d script was written:


# 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"


A line was added to /etc/rc.conf: factory_enable = “YES”. After which a test run was made: /usr/local/etc/rc.d/factory start and the script happily started. After checking the work of restart and stop as well, I was pleased with myself to go pour some tea. At the same time, in order to check the launch of the script in combat conditions, I sent a server to reboot.

When I returned with tea, I opened the browser and found that the serverside did not start. The forever log contained the following:
# 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


Thus, from the moment the service “started”, the child JS-process managed to fall / rise 11124 times already, while I was heating the tea bag in boiling water.

Whenever something is started from the console but does not work at startup in a “clean” environment, the inner voice whispers the same thing: “Environment variables!” But how so? I pointed out the HOME that everyone writes about, and NODE_ENV = production is necessary for express to work. What else does?

And you need to compare the difference between the user environment and the environment at startup. As a result of this comparison, three more environment variables were added to the “start” section in the rc.d script: USER, PATH and PWD. After that, the JS script started correctly. Actually the working version of the rc.d script began to look like this:

#!/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"


Having rummaged in "these your Internet", I was surprised at the lack of information about the fail-safe start of the node.js service in this way on a machine running FreeBSD. Actually what I decided to write about, it will suddenly be useful to someone.

Also popular now: