Init.d startup/shutdown script for Node.JS applications via forever

If you are like me and have multiple Node.JS applications running on a *NIX box, each managed by the ‘forever‘ which is described as “A simple CLI tool for ensuring that a given node script runs continuously (i.e. forever)” then chances are you’ve also wanted to add your applications to auto-start via init.d. Additionally, by having an init.d script for each application you’d be able to stop, restart, and check the status of each of your applications without having to get into pathing and changing users.

Please remember to look at all lines that say #CHANGEME and change the values to whatever custom values you need.

So, without further ado, I give you my forever-nodejs-init.d-script which I have adapted but not created from scratch (for the original source, see below):

#!/bin/bash
### BEGIN INIT INFO
# Provides:          my-app #CHANGEME Use your own app name
# Required-Start:    $local_fs $remote_fs $network $syslog $named
# Required-Stop:     $local_fs $remote_fs $network $syslog $named
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start/stop my node application #CHANGEME Use your own description
### END INIT INFO

#CHANGEME Add any exports/environment variables here

NAME=my-app #CHANGEME Use your own app name
SOURCE_DIR=/opt/my/app #CHANGEME Set this to the base directory of your node application
SOURCE_FILE=index.js #CHANGEME This is the 'index' js file that node should be set to run to start your application

user=node #CHANGEME Run the application as this user
pidfile=/var/run/$NAME.pid
forever_dir=/var/run/forever

node=node
forever=/usr/local/lib/node_modules/forever/bin/forever
sed=sed

export PATH=$PATH:/home/node/local/node/bin
export NODE_PATH=$NODE_PATH:/home/node/local/node/lib/node_modules

start() {
  echo "Starting $NAME node instance: "

  if [ "$foreverid" == "" ]; then
    # Create the pid file, making sure that 
    # the target use has access to them
    touch $pidfile
    chown $user $pidfile

    # Launch the application
    pushd $SOURCE_DIR > /dev/null
    sudo -u $user $forever start -d -p $forever_dir --pidFile $pidfile -a $SOURCE_FILE
    echo "sudo -u $user $forever start -d -p $forever_dir --pidFile $pidfile -a $SOURCE_FILE"
    RETVAL=$?
  else
    echo "Instance already running"
    RETVAL=0
  fi
}

stop() {
  echo -n "Shutting down $NAME node instance : "
  if [ "$foreverid" != "" ]; then
    $node $SOURCE_DIR/prepareForStop.js
    $forever stop -p $forever_dir $foreverid
  else
    echo "Instance is not running";
  fi
  RETVAL=$?
}

status() {
	VAL=`(cat ${pidfile} | xargs ps -p) | wc -l`
	if [[ "$VAL" == "2" ]]; then
		INFO=`sudo -u $user $forever list --plain | $sed -n 's/^data:\s\+\[\([0-9]\+\)\]\s\+.*\s\+'$pid'\s\+\S\+\s\+\([0-9]\+:[0-9]\+:[0-9]\+:[0-9]\+\.[0-9]\+\)\s*$/Fid \1 Uptime \2/p'`
		echo "Running ($INFO)"
		RETVAL=0
	else
		echo "Not running"
		RETVAL=-1
	fi
}

if [ -f $pidfile ]; then
  read pid < $pidfile
else
  pid=""
fi

if [ "$pid" != "" ]; then
  # Gnarly sed usage to obtain the foreverid.
  foreverid=`sudo -u $user $forever list --plain | $sed -n 's/^data:\s\+\[\([0-9]\+\)\]\s\+.*\s\+'$pid'\s\+\S\+\s\+[0-9]\+:[0-9]\+:[0-9]\+:[0-9]\+\.[0-9]\+\s*$/\1/p'`
else
  foreverid=""
fi

case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  status)
    status
    ;;
  *)
    echo "Usage:  {start|stop|status}"
    exit 1
    ;;
esac
exit $RETVAL

The above script was adapted and improved on from this blog post on Ex Ratione.

Thank you to Stephane (in comments) for improving the script further!

5 Comments

Stephane says:

Hi Petro,

Great script, you made my life simpler thanks to this !
One note though, I personally had to do one modification to your script

I changed the line :
$forever stop -p $forever_dir $id
into
$forever stop -p $forever_dir $foreverid

Thanks again for this !

* Petro says:

Thanks for the catch, that was actually the intention but I guess I made a typo 🙂 I have fixed it in the post now.

Stephane says:

Hi Petro,

First Merry X’mas to you, and else a second change I had to do in my case.

forever printed to me the following line when listing instances :
data: [1] v-1X /usr/bin/node app.js 2377 2383 /var/log/etap/forever.Portal.log 2:18:23:22.954

due to the v-1X the \w\+ was not working so I changed the status regular expression.
$sed -n ‘s/^data:\s\+\[\([0-9]\+\)\]\s\+.*\s\+’$pid’\s\+\S\+\s\+\([0-9]\+:[0-9]\+:[0-9]\+:[0-9]\+\.[0-9]\+\)\s*$/Fid \1 Uptime \2/p’

I also updated the pid finder regular expression
$sed -n ‘s/^data:\s\+\[\([0-9]\+\)\]\s\+.*\s\+’$pid’\s\+\S\+\s\+[0-9]\+:[0-9]\+:[0-9]\+:[0-9]\+\.[0-9]\+\s*$/\1/p’

I actually used part of the pid finder regular expression to ensure that $pid would match the last number and not the first one in case a forever process spawns another forever process.

Thanks again for your script.

* Petro says:

Thanks for the heads up Stephane, I’m sure others who come here to get the script will appreciate the changes. I have updated the post with the new regular expressions you have provided, if you could double check to make sure I didn’t screw it up that would be much appreciated! Merry Xmas to you as well, I am adding a ‘thank you’ to you at the bottom of the post for your contributions 🙂 Cheers.

Jeryl Cook says:

Nice Post, i used it :)..

made some changes though:

there are some changes that you may want to update…
i wanted to write to a log file with the same name as the application.
as well as use the timestamp feature within forever:

logfile=/var/log/$NAME.log

and

# Launch the application
pushd $SOURCE_DIR > /dev/null
sudo -u $user $forever set timestamp true

sudo -u $user $forever start -d -p $forever_dir –pidFile $pidfile -l $logfile -a $SOURCE_FILE

echo “sudo -u $user $forever start -d -p $forever_dir –pidFile $pidfile -l $logfile -a $SOURCE_FILE”

RETVAL=$?

Leave a Reply

Your email address will not be published.