5

I am using express and Connect Timeout Middleware to handle the timeouts.

It works great, but I the default node http server's timeout is set to two minutes.

Therefore if I want to set my timeout middleware to a value greater than two minutes, I also have to increase the http server timeout to be slightly bigger (otherwise my connect timeout handler is not called)

const app = express();
const http = new Http.Server(app);

http.setTimeout((4 * 60 * 1000) + 1); <-- Must set this

app.use(timeout('4m')); 

How can I avoid this ? Am I missing something ?

Scaraux
  • 3,841
  • 4
  • 40
  • 80
  • Nope, that's just how it works. If node closes the socket before your middleware times out the request, the handler will not be called because the request is closed at that point in time. https://github.com/expressjs/timeout/issues/32 – Kevin B Mar 26 '19 at 18:56

1 Answers1

6

If you want to use the connect-timeout middleware, you can't avoid it, since the middleware does not change the socket timeout, which defaults to 2 minutes.

There are two possible ways to avoid it, either using server.setTimeout() or request.setTimeout.

In case you only want to change the timeout to a few routes, and leave the default timeout to the rest, the recommended approach is to use: request.setTimeout

app.use('/some-routes', (req, res, next) => {
   req.setTimeout((4 * 60 * 1000) + 1);
   next();
}, timeout('4m'));

An alternative to setting the req.setTimeout to a value greater than the connect-timeout value, is dropping the connect-timeout middleware and using another work around, which is also not ideal.

You can check this old Node.js issue https://github.com/nodejs/node-v0.x-archive/issues/3460

function haltOnTimedout (req, res, next) {
  if (!req.timedout) next()
}

app.use('/some-routes', (req, res, next) => {
    req.setTimeout(4 * 60 * 1000); // No need to offset

    req.socket.removeAllListeners('timeout'); // This is the work around
    req.socket.once('timeout', () => {
        req.timedout = true;
        res.status(504).send('Timeout');
    });

    next();
});


app.use(haltOnTimedout);

// But if the timeout occurs in the middle of a route
// You will need to check if the headers were sent or if the request timedout

app.get('/some-routes', async(req, res, next) => {
  
  // some async processing...
  await asyncOperation();
  
  if (!res.headersSent) // or !req.timedout 
    res.send('done');
 
});
Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317
Marcos Casagrande
  • 37,983
  • 8
  • 84
  • 98