To prevent requests from taking too long, it’s a good idea to have a maximum processing time for requests.
We can do this by making requests that take too long to time out. The connect-timeout
middleware can help us do this.
In this article, we’ll look at how to use it to implement time out features in our app.
One Catch
This middleware sends a timeout response back to the client if a request exceeds the maximum time that we specify.
However, in the background, it’ll continue to run whatever was running before the request timed out.
Resources like CPU and memory will continue to be used until the process terminates.
We may need to end the process and free up any resources that it was using.
Usage
The timeout
function takes 2 arguments. The first is the time
for the maximum time for the request to process, and the second is an options
object.
Time
The time
is either a number in milliseconds or a string accepted by the ms
module.
On timeout, req
will emit timeout
.
Options
The options
object takes an optional
object that can have the following property:
respond
— controls if this module will response in the form of forwarding an error. If it’strue
, the timeout error is passed to thenext
so that we may customize the response behavior. The error has atimeout
property and status code 503. The default istrue
.
req.clearTimeout()
The clearTimeout
method clears the timeout on the request and it won’t fire for this request in the future.
req.timedout
A boolean that is true
if timeout
is fired and false
otherwise.
Example
We can use it as follows as top-level middleware. We have to stop the flow to the next middleware if the request timed out so they won’t run.
For example, we can write:
const express = require('express');
const bodyParser = require('body-parser');
const timeout = require('connect-timeout');
const app = express();
const haltOnTimedout = (req, res, next) => {
if (!req.timedout) {
next();
}
}
app.use(timeout('5s'))
app.use(bodyParser.json({ extended: true }))
app.use(haltOnTimedout)
app.get('/', (req, res) => {
res.send('success');
})
app.listen(3000);
Then our endpoints will time out after 5 seconds and only allow to proceed beyond the bodyParser
middleware if the request hasn’t timed out.
We can check time out by adding setTimeout
to our route handler as follows:
const express = require('express');
const bodyParser = require('body-parser');
const timeout = require('connect-timeout');
const app = express();
const haltOnTimedout = (req, res, next) => {
if (!req.timedout) {
next();
}
}
app.use(timeout('5s'))
app.use(bodyParser.json({ extended: true }))
app.use(haltOnTimedout)
app.get('/', (req, res) => {
setTimeout(() => {
res.send('success');
}, Math.random() * 7000);
})
app.listen(3000);
The some requests will time out and get us a 503 response.
We can catch the error and handle it ourselves as follows:
const express = require('express');
const bodyParser = require('body-parser');
const timeout = require('connect-timeout');
const app = express();
const haltOnTimedout = (req, res, next) => {
if (!req.timedout) {
next();
}
}
app.use(timeout('5s'))
app.use(bodyParser.json({ extended: true }))
app.use(haltOnTimedout)
app.get('/', (req, res, next) => {
setTimeout(() => {
if (req.timedout) {
next();
}
else {
res.send('success');
}
}, Math.random() * 7000);
})
app.use((err, req, res, next) => {
res.send('timed out');
})
app.listen(3000);
In the setTimeout
callback, we check the req.timedout
property and called next()
if it times out so that it’ll go to our error handler.
Note that we have the error handler after our route so calling next
will go to our error handler.
We should get timed out
if our request timed out instead of the error message and stack trace.
Conclusion
We can use the connect-timeout
middleware to implement time out functionality for our routes.
This sends a 503 response if a request times out, but it doesn’t clear all the resources that’s being used for the request and end the process that’s still running.
We can check if a request has timed out with the req.timedout
property.
Finally, we can catch the error by adding our own error handler after our routes and calling next
.