Monday, December 25, 2017

Configuring "forever" Script to Run a Process Forever

This document describes how to use the "forever" command to keep a script running forever. The "forever" command is poorly designed, and has a million pitfalls. Because of its poor design, "forever" is the worst of these sorts of programs, except for all the others. We'll show you how to work around all the pitfalls.

I have code that should run forever. In this case it's a service that connects to Firebase and implements a search. It should run forever, so that the search is fast: it keeps a local copy of the list of search targets, and then stores search results into Firebase.

It's easy to write a Node.js script do do the search. And you can run the script from the command line.
./search.node &
The problem is that the service stops when I close the window.

You can use nohup:
nohup ./search.node &
The script will continue to run when the window is closed. But if the script should terminate, nothing will restart it.

That's what "forever" is for.
npm install forever
Then
node_modules/forever/bin/forever start search.js
That command might work, except, as mentioned above, there are a million stupid little issues with "forever".

The first issue is that the "node" command on linux (Ubuntu, at least) often doesn't exist. It's called nodejs by default. If you add a symlink to /bin, that might not solve the problem because the default Node.js is old. The best way to get a latest Node.js is
npm install n
The "n" program is created so you can run multiple versions of Node.js on your computer. By default, the latest version is installed in /usr/local/bin/node. Your PATH environment variable probably includes /usr/local/bin early on, so you can run node from the command line.

Now, you'll get the latest version of Node.js, so things like Firebase will run correctly.

Now
node_modules/forever/bin/forever start search.js
will probably start your script.

Ok, but what happens if the server reboots, perhaps to get the latest security patches? You can configure your crontab to start "forever" at boot.
crontab -e
then add
@reboot (cd work/search && node_modules/forever/bin/forever start search.js)
and it probably won't work. Cron runs with a very limted path that doesn't include /usr/local/bin.

So, create the following script, called "run".
PATH=/usr/local/bin:$PATH
export FOREVER_ROOT=.forever
node node_modules/forever/bin/forever stopall
node node_modules/forever/bin/forever --minUptime 1000 --spinSleepTime 1000 start server.js
This script adds /usr/local/bin to the path. It then sets the root for all files created by forever to be .forever, in the current directory, rather than your home directory. It then stops any previously running forever scripts. It then starts forever and your script.

Now update your crontab.
@reboot (cd work/search && ./run)
Then reboot your server to test.

Others will tell you to use the package forever_service. It solves a lot of the same problems in an easier way. However, it violates one of my prime rules, that you should be able to configure your app without needing root access. The reasoning behind that rule is for another post.