node.js as serivce with upstart on centos

Recently I gave myself simple task to test out tiny node.js app on server. While starting it manually is no brainer but it made me think more when I wanted to make it work as background service.

Usually I do it in /etc/init.d/ folder by creating bash script and run it from there, it is reliable, it is how httpd starts. But after some googling I found people talking about upstart and monit, I did feel like caveman, but took it seriously and opened upstart cookbook and just started to evaluate how should I eat it and if it is poisonous.

So after some digging I did decide to run node.js with upstart just because its new to me and its philosophy of event driven approach seems close to node. But challenges just began.

Upstart is not supported in all distros, and I was lucky that centos supports it and has version pre-installed, but sadly its 0.6.5 which is away from now latest 1.5. I could have downloaded latest package and “try” to install it but I thought it is not worth the effort to just try out small node app.

Single instance

My upstart version is 0.6.5, so how should I take care of starting node as background service. Well first thing is to specify user for node to run. I did install node from binary tarball to /usr/share/node/node-v0.8.9-linux-x64, later created apps folder in /usr/share/node and added sample express3 app from node passport-local module examples. Then created user node and changed /usr/share/node ownership recursively to node user with chown -R node /usr/share/node.

By default app will not even start as it has some dependencies but those could be handled with npm which comes with node installation by default.

Next step was to start this app as a background service as title of this article says. For a service aka job to be started by upstart it is required to put *.conf file into /etc/init/ directory. In upstart 1.4 and upwards it could be placed into $home/.init/ but not in my case. Upstart is evented system so basically you react to events on system and do your stuff, you can also emit your own events and catch those in other scripts. So in my case I had to write simple script which listens to some sort of startup event and starts app after it gets one, so after reading docs and googling I came up with louischatriot’s script found on github:

# /etc/init/node.conf
description 'node system startup'
author 'ivarprudnikov.com'
env NAME=AppName
env LOG_FILE=/usr/share/node/some.log
env USER=node
env NODE_BIN=/usr/share/node/node-v0.8.9-linux-x64/bin/node
env SCRIPT_FILE=/usr/share/node/apps/examples/express3/app.js
start on runlevel [2345] stop on runlevel [016]
# Respawn in case of a crash, with default parameters
respawn
script
  # Make sure logfile exists and can be written by the user we drop privileges to
  touch $LOG_FILE
  chown $USER:$USER $LOG_FILE
  # recommended approach in case of su/sudo usage so that service does not fork
  exec su -s /bin/sh -c 'exec "$0" "$@"' $USER -- $NODE_BIN $SCRIPT_FILE >> $LOG_FILE 2>&1
end script
post-start script
echo "app $NAME post-start event" >> $LOG_FILE
end script

After saving file it is possible just to run it with initctl start node and app should be started.

But after restart I did not see it running, so what was wrong?? I found answer on serverfault and debug file to test out events fired in the system:

# /etc/init/debug.conf
start on ( starting JOB!=debug \
or started JOB!=debug \
or stopping JOB!=debug \
or stopped JOB!=debug )
script
exec 1>>/tmp/log.file
echo -n "$UPSTART_JOB/$UPSTART_INSTANCE ($0):$$:`date`:"
echo "Job $JOB/$INSTANCE $UPSTART_EVENTS. Environment was:"
env
echo
end scripts

So now after looking into /tmp/log.file I could choose which event to listen to and start node app. I changed:

start on runlevel [2345]
stop on runlevel [016]

to

start on started network
stop on stopping network

So now app is running in background, restarts in case of failure, starts on startup. Things to consider are hooking to events which are important to node, it would be possible to have nginx set up in this way and then:

start on ( started network and started nginx )
Newer post

Android sensors app

July 8, 2015
Subscribe to device sensors and store data locally. Later use a URL to send the aggregated data somewhere you need.
Continue reading