Skip to content

Commit

Permalink
Merge pull request #6 from amino/develop
Browse files Browse the repository at this point in the history
Error handling and maintenance mode fixes
  • Loading branch information
Carlos Rodriguez committed Mar 11, 2014
2 parents d5df2d9 + 151221b commit 4b3b4fa
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 54 deletions.
51 changes: 39 additions & 12 deletions bin/amino-gateway
Expand Up @@ -38,6 +38,10 @@ if (cluster.isMaster) {
cluster.fork();
}

cluster.on('disconnect', function (worker) {
console.error('worker ' + worker.process.pid + ' disconnected. killing...');
worker.kill();
});
cluster.on('exit', function (worker, code, signal) {
var exitCode = worker.process.exitCode;
console.error('worker ' + worker.process.pid + ' died (' + exitCode + '). restarting...');
Expand All @@ -54,6 +58,14 @@ if (cluster.isMaster) {
console.error('Maintenance mode', program.maintMode ? 'on' : 'off');
});

cluster.once('fork', function (worker) {
worker.once('message', function (msg) {
if (msg === 'maintMode') {
worker.send('maintMode:' + (program.maintMode ? 'on' : 'off'));
}
});
});

if (program.maintMode) {
console.error('Maintenance mode on');
}
Expand All @@ -63,18 +75,33 @@ else {
program.maintMode = !program.maintMode;
});

process.title = 'amino-gateway (worker)';
var server = amino.createGateway(program);
server.on('error', function (err) {
console.error(err, 'server error');
});
server.on('listening', function () {
if (program.setgid) {
process.setgid(program.setgid);
}
if (program.setuid) {
process.setuid(program.setuid);
// Get the current maintenance mode from cluster master before start
process.send('maintMode');
process.once('message', function (msg) {
var parts = msg.split(':');
if (parts[0] === 'maintMode') {
if ((parts[1] === 'on' && !program.maintMode) || (parts[1] === 'off' && program.maintMode)) {
program.maintMode = !program.maintMode;
}
}
startGateway();
});
server.listen(program.port);

process.title = 'amino-gateway (worker)';

function startGateway () {
var server = amino.createGateway(program);
server.on('error', function (err) {
console.error(err, 'server error');
});
server.on('listening', function () {
if (program.setgid) {
process.setgid(program.setgid);
}
if (program.setuid) {
process.setuid(program.setuid);
}
});
server.listen(program.port);
}
}
76 changes: 34 additions & 42 deletions index.js
Expand Up @@ -9,37 +9,32 @@ exports.attach = function (options) {
options || (options = {});
var amino = this;

var d = require('domain').create();
d.on('error', function (err) {
console.error('uncaught error!', err.stack || err);

try {
// make sure we close down within 30 seconds
var killtimer = setTimeout(function() {
process.exit(1);
}, 30000);
// But don't keep the process open just for that!
killtimer.unref();

// stop taking new requests.
server.close();

// Let the master know we're dead. This will trigger a
// 'disconnect' in the cluster master, and then it will fork
// a new worker.
cluster.worker.disconnect();
amino.createGateway = function (opts) {

// try to send an error to the request that triggered the problem
res.writeHead(500, {'content-type': 'text/plain'});
res.write('Internal server error. Please try again later.');
res.end();
} catch (err2) {
// oh well, not much we can do at this point.
console.error('Error sending 500!', err2.stack || err2);
}
});
var d = require('domain').create();
d.on('error', function (err) {
console.error('uncaught error!', err.stack || err);

try {
// make sure we close down within 30 seconds
var killtimer = setTimeout(function() {
process.exit(1);
}, 30000);
// But don't keep the process open just for that!
killtimer.unref();
// stop taking new requests.
server.close();

// Let the master know we're dead. This will trigger a
// 'disconnect' in the cluster master, and then it will fork
// a new worker.
cluster.worker.disconnect();
} catch (err2) {
// oh well, not much we can do at this point.
console.error('Error closing server', err2.stack || err2);
}
});

amino.createGateway = function (opts) {
opts = amino.utils.copy(opts);
var serviceSpec = new amino.Spec(opts.service);

Expand Down Expand Up @@ -79,18 +74,14 @@ exports.attach = function (options) {
if (opts.onError) {
opts.onError(err, req, res);
}
else {
// WebSockets have no res
else if (res && !res.headersSent) {
res.writeHead(500, {'content-type': 'text/plain'});
res.write('Internal server error. Please try again later.');
res.end();
}
}

// No longer supported by http-proxy -- problem?
// if (opts.sockets) {
// httpProxy.setMaxSockets(opts.sockets);
// }

if (options.maintPage) {
var maintPage = require('dish').file(options.maintPage);
}
Expand All @@ -102,7 +93,7 @@ exports.attach = function (options) {
var remoteIp = addr(req);
if (options.maintIps && ~options.maintIps.indexOf(remoteIp)) doProxy();
else {
maintPage(req, res, 500);
maintPage(req, res, 503);
}
}
else {
Expand All @@ -113,7 +104,9 @@ exports.attach = function (options) {
setupRequest(req, function (spec) {
req._spec = spec;
d.run(function () {
proxy.web(req, res, { target: spec });
proxy.web(req, res, { target: spec }, function httpErrorHandler (err, req, res) {
onReqError(err, req, res, req._sReq, req._spec);
});
});
});
}
Expand All @@ -123,15 +116,14 @@ exports.attach = function (options) {
setupRequest(req, function (spec) {
req._spec = spec;
d.run(function () {
proxy.ws(req, socket, head, { target: spec });
proxy.ws(req, socket, head, { target: spec }, function wsErrorHandler (err, req, socket) {
onReqError(err, req, null, req._sReq, req._spec);
socket.destroy();
});
});
});
});

proxy.on('error', function (err, req, res) {
onReqError(err, req, res, req._sReq, req._spec);
});

return server;
};
};

0 comments on commit 4b3b4fa

Please sign in to comment.