Skip to content

Commit

Permalink
Merge pull request #739 from wpreul/master
Browse files Browse the repository at this point in the history
Adding server.stop support for destroying connections after a timeout
  • Loading branch information
Eran Hammer committed Apr 6, 2013
2 parents d800e1a + 0e15d32 commit c1fc1c4
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 1 deletion.
26 changes: 25 additions & 1 deletion lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ internals.Server.prototype._start = function (callback) {
}

this._started = true;
this._connections = {};
this.listener.once('listening', function () {

var address = self.listener.address(); // Update the port and uri with what was actually bound
Expand All @@ -201,6 +202,17 @@ internals.Server.prototype._start = function (callback) {
return callback();
});

this.listener.on('connection', function(connection) {

var key = connection.remoteAddress + ':' + connection.remotePort;
self._connections[key] = connection;

connection.once('close', function() {

delete self._connections[key];
});
});

this.listener.listen(this.settings.port, this.settings.host);
};

Expand All @@ -219,14 +231,26 @@ internals.Server.prototype._stop = function (options, callback) {

options = options || {};
callback = callback || function () { };
options.timeout = options.timeout || 5000; // Default timeout to 5 seconds

if (!this._started) {
return callback();
}

self._started = false;

var timeoutId = setTimeout(function () {

Object.keys(self._connections).forEach(function (key) {

var connection = self._connections[key];
return connection && connection.destroy();
});
}, options.timeout);

self.listener.close(function () {

self._started = false;
clearTimeout(timeoutId);
callback();
});
};
Expand Down
86 changes: 86 additions & 0 deletions test/integration/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,90 @@ describe('Server', function () {
});
});
});

it('won\'t destroy connections until after the timeout', function (done) {

var server = Hapi.createServer(0);
server.start(function () {

var socket1 = new Net.Socket();
var socket2 = new Net.Socket();

socket1.once('error', function (err) {

expect(err.errno).to.equal('ECONNRESET');
});

socket2.once('error', function (err) {

expect(err.errno).to.equal('ECONNRESET');
});

socket1.connect(server.settings.port, server.settings.host, function () {

socket2.connect(server.settings.port, server.settings.host, function () {

server.listener.getConnections(function (err, count) {

expect(count).to.be.greaterThan(0);
var timer = new Hapi.utils.Timer();

server.stop({ timeout: 20 }, function () {

expect(timer.elapsed()).to.be.at.least(19);
done();
});
});
});
});
});
});

it('won\'t destroy connections if they close by themselves', function (done) {

var server = Hapi.createServer(0);
server.start(function () {

var socket1 = new Net.Socket();
var socket2 = new Net.Socket();

socket1.once('error', function (err) {

expect(err.errno).to.equal('ECONNRESET');
});

socket2.once('error', function (err) {

expect(err.errno).to.equal('ECONNRESET');
});

socket1.connect(server.settings.port, server.settings.host, function () {

socket2.connect(server.settings.port, server.settings.host, function () {

server.listener.getConnections(function (err, count) {

expect(count).to.be.greaterThan(0);
var timer = new Hapi.utils.Timer();

server.stop(function () {

server.listener.getConnections(function (err, count) {

expect(count).to.equal(0);
expect(timer.elapsed()).to.be.at.least(10);
done();
});
});

setTimeout(function () {

socket1.end();
socket2.end();
}, 10);
});
});
});
});
});
});

0 comments on commit c1fc1c4

Please sign in to comment.