Skip to content

Instantly share code, notes, and snippets.

@slattery
Last active September 16, 2015 16:07
Show Gist options
  • Save slattery/0fd0ce6e62f6fb185ea9 to your computer and use it in GitHub Desktop.
Save slattery/0fd0ce6e62f6fb185ea9 to your computer and use it in GitHub Desktop.
pm2 actionhero startup

I like using pm2 to manage node starts and restarts, including actionhero.

Node falls right on its face if anyone's code goes through an uncaught exception. We're not at all used to that in Apacheland. pm2 does whatever forever does for node, plus some more. pm2 will output a nice report for web boards, etc. And pm2 is smart about restarting, as well as bailing out if the app is faulty and restarts 15 times in a row due to a launch error. Plus it will combine log output for us if we are running a few servers on the machine.

# NOTE: you may need g++ if it is not installed
# apt-get install g++
npm install -g pm2
pm2 startup ubuntu

The pm2 startup ubuntu command should give us the init script needed to run pm2 on startup. It gets installed to /etc/init.d/pm2-init.sh. pm2 keeps a cache of commands it had running when it shuts down. So we'll be launching my_ah_server using pm2 now and it will restart once the machine does. Let's put pm2 in our runlevels:

update-rc.d pm2-init.sh defaults

pm2 will take a config file and export environment variables for us, which is handy when we are running actionhero in a profile that is not 'production'. For instance we run a profile called 'singlebox' where our apache and ah are on the same box doing different parts of our app. So we need to run ah with a NODE_ENV of 'singlebox'.

mike@dev:~$ more /etc/pm2/my_ah_server.json 
[{
    "name"       : "my_ah_server",
    "script"     : "/srv/ah/my_ah_server/node_modules/.bin/actionhero",
    "env"        : {
      "NODE_ENV" : "singlebox",
      "ACTIONHERO_CONFIG" : "/srv/ah/my_ah_server/config/config.js",
      "PROJECT_ROOT"       : "/srv/ah/my_ah_server/",
      "ACTIONHERO_ROOT"    : "/srv/ah/my_ah_server/node_modules/actionhero"
    },
    "instances"  : "1",
    "error_file" : "/var/log/pm2/my_ah_server.err",
    "out_file"   : "/var/log/pm2/my_ah_server.out",
    "pid_file"   : "/var/log/pm2/my_ah_server.pid",
    "exec_mode"  : "fork_mode"
}]

We can now try to launch my_ah_server

pm2 -v start /etc/pm2/my_ah_server.json

If that works it should keep my_ah_server in pm2's own startup process by virtue of pm2 dumping the current list of processes into a file on shutdown that gets consulted on start.

However, you might want to dedicate a pm2 init script to that server profile.

A good additional step to make sure my_ah_server loads is to create a separate init script per ah site or config profile, and run the one you want on boot. You'd want to run this after pm2 launches. So after you place your single job init script in /etc/init.d/, run the update command with a higher launch number.

update-rc.d pm-myahserver.sh defaults 91

Then you should be able to control that one job

service my_ah_server start
service my_ah_server stop
service my_ah_server reload

pm-myahserver.sh:

#!/bin/bash
# chkconfig: 2345 98 02
#
# description: PM2 next gen process manager for Node.js
# processname: pm2
#
### BEGIN INIT INFO
# Provides:          pm2
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Should-Start: $network
# Should-Stop: $network
# Default-Start:        2 3 4 5
# Default-Stop:         0 1 6
# Short-Description: PM2 init script
# Description: PM2 is the next gen process manager for Node.js
### END INIT INFO

PM2=/usr/local/lib/node_modules/pm2/bin/pm2
USER=root

NODE=/usr/local/bin/node
NAME=my_ah_server
APP_CFG=/etc/pm2/my_ah_server.json
APP_NAME=$NAME

export PATH=$PATH:/usr/local/bin
export HOME="/root"

super() {
    sudo -Ei -u $USER PATH=$PATH $*
}

start() {
    echo "Starting $NAME"
    #super $PM2 resurrect
    super $NODE $PM2 start $APP_CFG --name $APP_NAME

}

stop() {
    echo "Starting $APP_NAME"
    super $NODE $PM2 stop $APP_NAME
}

restart() {
    echo "Restarting $NAME"
    super $NODE $PM2 restart $APP_NAME

}

reload() {
    echo "Reloading $NAME"
    super $NODE $PM2 reload $APP_NAME
}

status() {
    echo "Status for all in $NAME:"
    super $PM2 list
    RETVAL=$?
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    status)
        status
        ;;
    restart)
        restart
        ;;
    reload)
        reload
        ;;
    *)
        echo "Usage: {start|stop|status|restart|reload}"
        exit 1
        ;;
esac
exit $RETVAL
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment