Running Node Apps with Forever

Introduction

For many people, actually running your code in a production environment is an afterthought, and just writing the code is where the real challenge is at. While this is mostly true in my experiences, finding a reliable and easy way to run your app can be pretty difficult itself.

There are a few things you need to consider when running your app(s).

  • Where will the output/logs go?
  • What happens if the app crashes?
  • How do I keep track of all my daemon processes?
  • How do I provide configurations for each process?

This is where the Node forever package is really useful. It helps you easily manage all of the above problems and more, which I'll describe in the next few sections.

What is Forever?

forever is a command-line utility for Node applications written entirely in JavaScript. It is meant to simplify your life in a production environment by managing (starting, stopping, restarting, etc) Node processes and their configurations. You can use it on the command line or programmatically (via forever-monitor) within your Node code.

You can specify these configurations via the command line or a JSON configuration file. I personally prefer the JSON file since you can configure multiple Node processes in a single file, making it easy to launch all of your processes at once. This way I don't hesitate to break up a big monolith in to multiple independent services since managing them will be much easier thanks to utilities like forever.

It works underneath by running Flatiron server as a daemon process to manage your other daemon processes, so if/when your code fails and crashes, forever will be there to automatically restart it and hopefully avoid downtime for your users. Running forever with a Flatiron server is an easy way to keep the utility up and running while monitoring for user input, and thanks to the CLI plugin this was easy for the forever developers to do. If you're going to create a program like forever (i.e. a long-running daemon process that receives user commands) then I'd highly recommend you do it this way. It will make things a whole lot easier.

The interprocess communication happens via sockets, which is handled by the high-level nssocket library. The socket files that allow communication to be re-opened between processes reside in [forever.root]/socks. Naturally, the messages between the processes are serialized as JSON. It's another helpful library to check out if you ever want event-based socket communication.

I should note, one important feature about forever (and other process management tools like it) is that you can use it for non-Node applications as well, like Python, Ruby, etc. The -c, or command flag (which you'll see later), let's you tell forever how to run your app. Using this, you can tell it to use any other interpreter for execution, like Python:

$ forever start -c python py_script.py

So even if you don't like Node, or just need to use a different language for a project, keep in mind that this is still useful to you.

How to use Forever

Ok, on to the important part, how to actually use the damn thing. Let's start out with a simple example, like just starting and stopping a web-app. For our example, we'll be starting and stopping a "hello world" Express server:

// index.js

var express = require('express');  
var app = express();

app.get('/', function (req, res) {  
  res.send('Hello World!');
});

var server = app.listen(8080);  

Install forever with npm install forever -g, and start the server with:

$ forever start -a index.js

This will launch the Express app as a background process. The -a flag appends logs to the default log file located in forever's root directory (~/.forever by default on Unix systems). You won't be able to start the app without this flag if the log file already exists.

Inspect the running process with forever list:

info:    Forever processes running  
data:        uid  command                                         script   forever pid   id logfile                        uptime  
data:    [0] moMB /Users/scott/.nvm/versions/node/v4.1.2/bin/node index.js 21389   21390    /Users/scott/.forever/moMB.log 0:0:0:3.345  

To stop the process, just refer to it by id (21390), uid (moMB), pid (21389), index (0), or script name (index.js):

$ forever stop index.js

While this is nice, it could be better. index.js isn't very unique to our app, and the PID is hard to remember, so why give it a better name? That way you don't have to keep running forever list to get info on your running process.

$ forever start -a --uid myapp index.js

Now you can just stop it with:

$ forever stop myapp

Two arguments on the command line isn't so bad, but it can become a bit much when you start adding arguments for log files, different Node executables, working directories, and more. So instead of specifying everything on the command line, you can use a JSON configuration file like this:

{
    // Comments are allowed!
    "uid": "myapp",
    "append": true,
    "watch": true,
    "script": "index.js",
    "sourceDir": "/home/scott/myapp",
    "command": /Users/scott/.nvm/versions/node/v4.1.2/bin/node
}

Assuming this file is in your current working directory and named forever.json, use it like this:

$ forever start ./forever.json

As you can see, you can even tell forever which version of Node to use, which is really convenient when you have multiple apps on a single server that require different versions (like the io.js fork).

[
  {
    // App using Node v0.11.8
    "uid": "myapp1",
    "append": true,
    "watch": true,
    "script": "index.js",
    "sourceDir": "/Users/scott/myapp1",
    "command": "/Users/scott/.nvm/versions/node/v0.11.8/bin/node"
  },
  {
    // App using io.js
    "uid": "myapp2",
    "append": true,
    "watch": true,
    "script": "index.js",
    "sourceDir": "/Users/scott/myapp2",
    "command": "/Users/scott/.nvm/versions/io.js/v2.2.1/bin/node",
    "args": ["--port", "8080"]
  }
]

Conclusion

There are a few tools to help you run Node apps, most notably forever and pm2. I've tried both and thought forever was a bit easier to use (mostly just because it's simpler and has less features/options to worry about), while pm2 is more powerful. If you're really feeling ambitious, you can try out pm2's cluster mode or API to help monitor metrics about your running app.

What other interesting configurations and uses do you have for process management tools like forever? Let us know in the comments!