mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Short socket timeout while no pending request. Long timeout with pending req
This commit is contained in:
@@ -46,7 +46,14 @@ StreamServer = function () {
|
||||
if (!Package.webapp) {
|
||||
throw new Error("Cannot create a DDP server without the webapp package");
|
||||
}
|
||||
// Install the sockjs handlers, but we want to keep around our own particular
|
||||
// request handler that adjusts idle timeouts while we have an outstanding
|
||||
// request. This compensates for the fact that sockjs removes all listeners
|
||||
// for "request" to add its own.
|
||||
Package.webapp.WebApp.httpServer.removeListener('request', Package.webapp.WebApp._timeoutAdjustmentRequestCallback);
|
||||
self.server.installHandlers(Package.webapp.WebApp.httpServer);
|
||||
Package.webapp.WebApp.httpServer.addListener('request', Package.webapp.WebApp._timeoutAdjustmentRequestCallback);
|
||||
|
||||
Package.webapp.WebApp.httpServer.on('closing', function () {
|
||||
_.each(self.open_sockets, function (socket) {
|
||||
socket.end();
|
||||
|
||||
@@ -12,6 +12,9 @@ var optimist = Npm.require('optimist');
|
||||
var useragent = Npm.require('useragent');
|
||||
var send = Npm.require('send');
|
||||
|
||||
var SHORT_SOCKET_TIMEOUT = 3*1000;
|
||||
var LONG_SOCKET_TIMEOUT = 120*1000;
|
||||
|
||||
WebApp = {};
|
||||
WebAppInternals = {};
|
||||
|
||||
@@ -196,6 +199,23 @@ Meteor.startup(function () {
|
||||
});
|
||||
|
||||
|
||||
|
||||
// When we have a request pending, we want the socket timeout to be long, to
|
||||
// give ourselves a while to serve it, and to allow sockjs long polls to
|
||||
// complete. On the other hand, we want to close idle sockets relatively
|
||||
// quickly, so that we can shut down relatively promptly but cleanly, without
|
||||
// cutting off anyone's response.
|
||||
WebApp._timeoutAdjustmentRequestCallback = function (req, res) {
|
||||
req.setTimeout(LONG_SOCKET_TIMEOUT); // this is really just req.socket.setTimeout(LONG_AMOUNT);
|
||||
// Insert our new finish listener to run BEFORE the existing one which removes the response from the socket.
|
||||
var finishListeners = res.listeners('finish');
|
||||
res.removeAllListeners('finish');
|
||||
res.on('finish', function () {
|
||||
res.setTimeout(SHORT_SOCKET_TIMEOUT); // again, basically just res.socket.setTimeout
|
||||
});
|
||||
_.each(finishListeners, function (l) { res.on('finish', l); });
|
||||
};
|
||||
|
||||
var runWebAppServer = function () {
|
||||
var shuttingDown = false;
|
||||
// read the control for the client we'll be serving up
|
||||
@@ -417,42 +437,21 @@ var runWebAppServer = function () {
|
||||
var httpServer = http.createServer(app);
|
||||
var onListeningCallbacks = [];
|
||||
|
||||
var longPollingSockets = {};
|
||||
|
||||
// After 5 seconds of a socket being open, assume it is a long-polling
|
||||
// connection that we have to keep track of to shut down when we're shutting
|
||||
// down the server overall.
|
||||
httpServer.setTimeout(5000, Meteor.bindEnvironment(function (socket) {
|
||||
if (shuttingDown) {
|
||||
socket.end();
|
||||
} else {
|
||||
socket._meteorLongPollingId = Random.id();
|
||||
longPollingSockets[socket._meteorLongPollingId] = socket;
|
||||
// give the socket another minute to live.
|
||||
var destroy = Meteor.setTimeout(function () {
|
||||
delete longPollingSockets[socket._meteorLongPollingId];
|
||||
socket.removeListener('close', onClose);
|
||||
socket.destroy();
|
||||
}, 60*1000);
|
||||
httpServer.setTimeout(SHORT_SOCKET_TIMEOUT);
|
||||
|
||||
var onClose = function () {
|
||||
delete longPollingSockets[socket._meteorLongPollingId];
|
||||
Meteor.clearTimeout(destroy);
|
||||
};
|
||||
socket.on('close', onClose);
|
||||
}
|
||||
}, function (err) {
|
||||
console.log(err);
|
||||
}));
|
||||
// Do this here, and then also in livedata/stream_server.js, because
|
||||
// stream_server.js kills all the current request handlers when installing its
|
||||
// own.
|
||||
httpServer.on('request', WebApp._timeoutAdjustmentRequestCallback);
|
||||
|
||||
|
||||
// For now, handle SIGHUP here. Later, this should be in some centralized
|
||||
// Meteor shutdown code.
|
||||
process.on('SIGHUP', Meteor.bindEnvironment(function () {
|
||||
shuttingDown = true;
|
||||
_.each(longPollingSockets, function (socket, id) {
|
||||
socket.end();
|
||||
});
|
||||
// tell others with websockets open that we plan to close this.
|
||||
httpServer.emit('closing');
|
||||
httpServer.close( function () {
|
||||
|
||||
Reference in New Issue
Block a user