We're currently developing a website (TYPO3 under Apache) for a customer that is supported by a node.js/socket.io application that provides realtime updates to the content served from the CMS.
As this is our first node.js project I don't have any best practices to go by when it comes to 'the perfect setup' so I've spent some time researching deployment techniques.
A couple of questions remain for me to achieve a good setup which:
Is easy for the customer to deploy. This is very important because our website will be integrated in their 'live' TYPO3 installation which serves an abundance of websites and is running on servers which aren't managed by the customer but another (centralized) organization which makes support calls and server changes a slow process.
Should be easy to update. As mentioned requesting restarts and making server changes is a slow process, so idealy the node installation should restart / update when it receives changes that are pushed onto the live installion using git
.
Deployment
The general consensus seems to be to use forever
when it comes to deploying node applications to keep them running. I've tested forever
, and it seems to work fine when installed by npm install forever -g
(global). This would require external assistance to globally install on the live environment though, so I'd prefer to have it running from the application's node_modules
directory, but I haven't been able to create a solid wrapper to do so.
Additionally, forever
works fine, but it has to be started manually. What would be the best approach to ensure that it gets started on server boot and keeps running?
init.d
script?forever
status? Rapid development / Restart on update
We're currently still in the development stage of the project and every time I make changes to the node.js application I manually restart node
or forever
. This works, but is far from ideal.
There are several smaller npm
modules that check for file modifications and restart node
upon detected changes, like:
forever
)Does anyone have experience with any of these?
Update: Why don't you just use Cluster?
The Cluster module provides similar functionality through the reload mechanism, but doesn't work with Node 0.5+. The core Cluster module (Node 0.6+) that replaced it doesn't have all these features but only provides clustering. Which in turn doesn't play well with socket.io. At least not without using Redis (which is a problem for us, because we can't force another prereq service to the customer).
--
Obviously I'm trying to find the most stable solution that combines an update-restarter with forever
before handing over the project to the customer and I'm really hoping anyone has produced a proven combination of techniques.
Combining all knowledge gathered (Big thanks to Julian Knight for the ideas) and methods tested in the past week, I've decided to settle for the deployment solution described below (I thought I'd be nice to share to help others with comparable questions):
Auto-restarting on script errors and automatic reloading on script changes is handled by forever, as it also includes a script watch, as long as Forever is spawned from within a node.js script.
To do so, I've added a server.js
to launch the app.js
script we actually want to run:
server.js
var forever = require('forever'),
child = new(forever.Monitor)('app.js', {
'silent': false,
'pidFile': 'pids/app.pid',
'watch': true,
'watchDirectory': '.', // Top-level directory to watch from.
'watchIgnoreDotFiles': true, // whether to ignore dot files
'watchIgnorePatterns': [], // array of glob patterns to ignore, merged with contents of watchDirectory + '/.foreverignore' file
'logFile': 'logs/forever.log', // Path to log output from forever process (when daemonized)
'outFile': 'logs/forever.out', // Path to log output from child stdout
'errFile': 'logs/forever.err'
});
child.start();
forever.startServer(child);
This watches all files in the application directory for changes and restarts the script running in forever
as soon as one changes. Because the logs and pidfile are in subdirectories of the application, those have to be ignored from the file watch, or the script will loop restarts:
.foreverignore
pids/**
logs/**
To make this all start on system boot and enabling us to easily control the service using start node-app
and stop node-app
we use Ubuntu's Upstart.
I've combined two examples (this and this one) into one that does the job quite well:
/etc/init/node-app.conf
# This is an upstart (http://upstart.ubuntu.com/) script
# to run the node.js server on system boot and make it
# manageable with commands such as
# 'start node-app' and 'stop node-app'
#
# This script is to be placed in /etc/init to work with upstart.
#
# Internally the 'initctl' command is used to manage:
# initctl help
# initctl status node-app
# initctl reload node-app
# initctl start node-app
description "node.js forever server for node-app"
author "Remco Overdijk <[email protected]>"
version "1.0"
expect fork
# used to be: start on startup
# until we found some mounts weren't ready yet while booting:
start on started mountall
stop on shutdown
# Automatically Respawn:
respawn
respawn limit 99 5
env HOME=/home/user/node-app-dir
script
# Not sure why $HOME is needed, but we found that it is:
export HOME=$HOME
chdir $HOME
exec /usr/local/bin/node server.js > logs/node.log &
end script
#post-start script
# # Optionally put a script here that will notifiy you node has (re)started
# # /root/bin/hoptoad.sh "node.js has started!"
#end script
As Kevin wisely mentions in his article it's unwise to run node as root, so we'll change that to exec sudo -u www-data /usr/local/bin/node
when we move to new servers next week.
So, forever
gets started automatically by node server.js
which gets launched by upstart
, and monitors for crashes and file changes, keeping the entire setup running as long as we want.
I hope this helps anyone.