1

The original post for reference is here: Express.js Response Timeout

I'm trying to incorporate a timeout here, the response takes 10 sec and the timeout will be thrown in 5 sec, just for testing

    const express = require('express');
    const app = express();
    const port = 3000;


app.use(function(req, res, next){
    res.setTimeout(5000, function(){
        console.log('Request has timed out.');
            return res.json({succes: false, message: "request timeout"});         
        });
        console.log("calling next");
    next();
});

const asyncWork = () => {
  return new Promise((resolve,reject) => {
    setTimeout(() => {
      console.log("after 15 sec");
      resolve({"id": 1});
    },10000)
  });
};

app.get('/', async(req, res) => {
   const data = await asyncWork();
   res.json(data);
});

const server = app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
})

I'm able to achieve the request timeout message but it's also trying to execute and the response from asyncWork which throws an uncaughtPromiseRejectionWarning which I think is because it's trying to send 2 response.

I'm new to express so any suggestion or advice would help

1 Answers1

0

There are some timeout capabilities built into Express, but if you're trying to implement your own, then you will just need to check if the response has already been sent to avoid the warning about trying to send yet another response. Depending upon what your asynchronous operation is, there might be ways to abort it. But, for a generic asynchronous operation, you can just let it finish and then before sending a response, check if a response has already been sent.

const express = require('express');
const app = express();
const port = 3000;


app.use(function (req, res, next) {
    res.setTimeout(5000, function () {
        console.log('Request has timed out.');
        return res.json({ succes: false, message: "request timeout" });
    });
    console.log("calling next");
    next();
});

const asyncWork = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log("after 10 sec");
            resolve({ "id": 1 });
        }, 10000)
    });
};

app.get('/', async (req, res) => {
    const data = await asyncWork();
    if (res.writableEnded || res.writableFinished || res.headersSent) {
        console.log("response timed out so can't send data");
    } else {
        res.json(data);
    }
});

const server = app.listen(port, () => {
    console.log(`Example app listening on port ${port}`);
});

If you had to do this in a lot of places, you could make your own version of res.json() like res.jsonCheck() that has the check built into it.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Thanks a lot, this definitely worked. But my other question is that even though I'm able to send timeout response (after 5 sec), the other async work is still going on (taking 10 sec), will it not affect the latency cause after timeout I don't want to proceed with whatever other task it's running and abort it. Is there a way to handle that ? – AYUSH KUMAR ARYAL Mar 13 '23 at 03:21
  • @AYUSHKUMARARYAL - Aborting an existing asynchronous operation is very specific to the type of operation. Some you can, some you can't. You don't show a real asynchronous operation here, just a timer. You could abort the timer with `clearTimeout()` if you kept track of the `timerID`. There is no generic way to abort whatever is going on as part of this request handler. – jfriend00 Mar 13 '23 at 03:24
  • Got it. But in such scenarios should we try to abort existing asynchronous operations ? What would be the best practise ? Let's say instead of this asyncWork I was fetching from database, e.g mongodb and let's assume it took like 10 sec again. Should I abort that database operation ? – AYUSH KUMAR ARYAL Mar 13 '23 at 03:29
  • @AYUSHKUMARARYAL - It really depends upon the circumstance. If it's a really expensive asynchronous operation and there's a clean way to abort it and it times out frequently, then perhaps it's worth investing in aborting it. But, usually a timeout is not an expected and regular operation so you don't worry about aborting the other operation. – jfriend00 Mar 13 '23 at 03:32