Deployment
My choice for deployment is using fleet by substack
I deploy on SmartOS and have the fleet hub and drones running as services which automatically get restarted.
I am working on dispatcher which is a front-end to fleet. Dispatcher will allow to you keep all your repos in a central place such as github or bitbucket and then deploy the latest code from your central git server
Load Balancing
See my answer here for setting up an http and an https server. In my applications the http server is actually another node-http-proxy server. In this setup my application can consist of many small services that are registered with seaport
Routing http server
var http = require('http')
var https = require('https')
var httpProxy = require('http-proxy');
var seaport = require('seaport');
var fs = require('fs')
var inspect = require('eyespect').inspector();
var express = require('express')
function router(data, cb) {
var app = express()
var config = data.config
var logger = data.logger
var appPort = config.get('application:port');
var routerConfig = config.get('router')
var seaHost = config.get('seaport:host')
var seaPort = config.get('seaport:port')
var ports = seaport.connect(seaPort, seaHost)
var proxy = new httpProxy.RoutingProxy();
app.use(express.methodOverride());
app.use(app.router)
var server = http.createServer(app)
app.all('/api/:service/*', function (req, res) {
var service = req.params.service
var ps = ports.query(service);
if (!ps || ps.length === 0) {
ps = null
unavailable(req, res, service, logger);
service = null
return
}
var item = ps[0]
// remove /api/service/ from start of the url
var newURL = req.url.replace(/^\/api\/.*?\//, '/')
logger.debug('proxying to api service', {
role: router,
service: service,
url: req.url,
newURL: newURL
})
req.url = newURL
proxy.proxyRequest(req, res, {
host: item.host,
port: item.port
});
item = null
})
var pong = 'PONG'
app.get('/ping', function (req, res) {
res.send(pong)
})
app.get('/services', function (req, res) {
return showServices(req, res, ports)
})
app.all('/*', function (req, res) {
var service = 'web'
var ps = ports.query(service);
if (!ps || ps.length === 0) {
unavailable(req, res, service, logger);
service = null
ps = null
return
}
proxy.proxyRequest(req, res, {
host: ps[0].host,
port: ps[0].port
});
ps = null
})
var serverPort = routerConfig.port
server.listen(serverPort, function (err, reply) {
if (err) { return cb(err); }
logger.debug('router application online', {
type: 'router',
port: serverPort
});
var output = {
port: serverPort,
server: server
}
cb(null, output)
});
}
function showServices(req, res, ports) {
var ps = ports.query();
var data = {
message: 'Current services registered',
services: ps
}
res.writeHead(200)
return res.end(JSON.stringify(data))
}
function isServicesURL(url) {
var pattern = /^\/services/i;
return pattern.test(url)
}
function unavailable(req, res, service, logger ) {
var resData = {
error: 'service unavailable',
message: 'no servers are available to serve your request',
url: req.url,
role: 'router'
service: service
};
logger.debug('router service unavailable', {
role: 'router',
responseData: resData
})
res.writeHead(500);
return res.end(JSON.stringify(resData));
}
module.exports = router;
spinUpRouter.js this is the node process that is actually spawned by fleet
var inspect = require('eyespect').inspector()
var assert = require('assert')
var fs = require('fs')
var routerLib = require('./index.js');
var optimist = require('optimist');
var nconf = require('nconf')
var argv = optimist.demand(['config']).argv;
var configFilePath = argv.config
assert.ok(fs.existsSync(configFilePath), 'config file not found at path: ' + configFilePath);
var config = nconf.argv().env().file({file: configFilePath});
var logger = require('loggly-console-logger')
var routerData = {
config: config,
logger: logger
}
logger.debug('spinning up router', {
type: 'router',
configFilePath: configFilePath
})
routerLib(routerData, function (err, server) {
inspect('router online')
})
Logging
I use winston to manage my logs. More specifically I use the console and Loggly transports. I do this so much I have wrapped it up into a module loggly-console-logger