Skip to content

Commit

Permalink
Added "destroy" method to HTTP, used in .lower() for clean shutdown.
Browse files Browse the repository at this point in the history
  • Loading branch information
sgress454 committed Feb 2, 2016
1 parent 71db368 commit 9168001
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 22 deletions.
78 changes: 56 additions & 22 deletions lib/app/lower.js
Expand Up @@ -17,15 +17,25 @@ var _ = require('lodash');
* @api public
*/

module.exports = function lower(cb) {
module.exports = function lower(options, cb) {
var sails = this;

sails.log.verbose('Lowering sails...');

// Options are optional
if ('function' == typeof options) {
cb = options;
options = null;
}

// Callback is optional
cb = cb || function(err) {
if (err) return sails.log.error(err);
};

options = options || {};
options.delay = options.delay || 100;

// Flag `sails._exiting` as soon as the app has begun to shutdown.
// This may be used by hooks and other parts of core.
// (e.g. to stop handling HTTP requests and prevent ugly error msgs)
Expand Down Expand Up @@ -62,24 +72,37 @@ module.exports = function lower(cb) {
async.series([

function shutdownSockets(cb) {
if (!_.isObject(sails.hooks) || !sails.hooks.sockets) {

// If the sockets hook is disabled, skip this.
// Also skip if the socket server is piggybacking on the main HTTP server, to avoid
// the onClose event possibly being called multiple times (because you can't tell
// socket.io to close without it trying to close the http server). If we're piggybacking
// we'll call sails.io.close in the main "shutdownHTTP" code below.
if (!_.isObject(sails.hooks) || !sails.hooks.sockets || (sails.io.httpServer && sails.hooks.http.server === sails.io.httpServer)) {
return cb();
}

try {
sails.log.verbose('Shutting down socket server...');
var timeOut = setTimeout(cb, 100);
sails.io.server.unref();
sails.io.server.close();
sails.io.server.on('close', function() {
sails.log.verbose('Socket server shut down successfully.');
clearTimeout(timeOut);
cb();
});
timeOut = setTimeout(function() {
sails.io.httpServer.removeListener('close', onClose);
return cb();
}, 100);
sails.io.httpServer.unref();
sails.io.httpServer.once('close', onClose);
sails.io.close();
} catch (e) {
sails.log.verbose("Error occurred closing socket server: ", e);
clearTimeout(timeOut);
cb();
}

function onClose() {
sails.log.verbose('Socket server shut down successfully.');
clearTimeout(timeOut);
cb();
}

},

function shutdownHTTP(cb) {
Expand All @@ -92,25 +115,36 @@ module.exports = function lower(cb) {
try {
sails.log.verbose('Shutting down HTTP server...');

// Give the server 100ms to close all existing connections
// and emit the "close" event. After that, unbind our
// "close" listener and continue (this prevents the cb
// from being called twice).
timeOut = setTimeout(function() {
sails.hooks.http.server.removeListener('close', onClose);
return cb();
}, 100);

// Allow process to exit once this server is closed
sails.hooks.http.server.unref();

// Stop the server from accepting new connections
sails.hooks.http.server.close();
// If we have a socket server and it's piggybacking on the main HTTP server, tell
// socket.io to close now. This may call `.close()` on the HTTP server, which will
// happen again below, but the second synchronous call to .close() will have no
// additional effect. Leaving this as-is in case future versions of socket.io
// DON'T automatically close the http server for you.
if (sails.io && sails.io.httpServer && sails.hooks.http.server === sails.io.httpServer) {
sails.io.close();
}

// If the "hard shutdown" option is on, destroy the server immediately,
// severing all connections
if (options.hardShutdown) {
sails.hooks.http.destroy();
}
// Otherwise just stop the server from accepting new connections,
// and wait options.delay for the existing connections to close
// gracefully before destroying.
else {
timeOut = setTimeout(sails.hooks.http.destroy, options.delay);
sails.hooks.http.server.close();
}

// Wait for the existing connections to close
sails.hooks.http.server.on('close', onClose);
sails.hooks.http.server.once('close', onClose);

} catch (e) {
sails.log.verbose("Error occurred closing HTTP server: ", e);
clearTimeout(timeOut);
cb();
}
Expand Down
19 changes: 19 additions & 0 deletions lib/hooks/http/initialize.js
Expand Up @@ -48,6 +48,25 @@ module.exports = function(sails) {
sails.hooks.http.server = createServer(serverOptions, sails.hooks.http.app);
} else sails.hooks.http.server = createServer(sails.hooks.http.app);

// Keep track of all connections that come in, so we can destroy
// them later if we want to.
var connections = {};

sails.hooks.http.server.on('connection', function(conn) {
var key = conn.remoteAddress + ':' + conn.remotePort;
connections[key] = conn;
conn.on('close', function() {
delete connections[key];
});
});

// Create a `destroy` method we can use to do a hard shutdown of the server.
sails.hooks.http.destroy = function(cb) {
sails.log.verbose("Destroying http server...");
sails.hooks.http.server.close(cb);
for (var key in connections)
connections[key].destroy();
};

// Configure views if hook enabled
if (sails.hooks.views) {
Expand Down

0 comments on commit 9168001

Please sign in to comment.