Connect/Express Request Timeout Middleware

1.9.1 · active · verified Wed Apr 22

connect-timeout is a middleware for Connect and Express applications designed to terminate long-running HTTP requests after a specified duration. The current stable version is 1.9.1. It provides functionality to emit a 'timeout' event on the request object and, optionally, forward a 503 Service Unavailable error to the next middleware. While it flags timed-out requests, it's crucial to understand that it does not inherently stop the underlying server-side processing of the request; developers must explicitly check `req.timedout` to halt further execution and manage resource consumption. Its primary differentiation is its tight integration with the Connect/Express middleware pattern, allowing for flexible placement in the middleware chain, though it warns against top-level usage without precautions. Release cadence appears moderate, with dependency updates and minor fixes.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to apply `connect-timeout` to an Express route, implement a `haltOnTimedout` helper middleware to prevent further processing, and catch timeout errors. It simulates a slow asynchronous task to trigger the timeout and shows how to check `req.timedout` before responding.

import express from 'express';
import timeout from 'connect-timeout';

const app = express();

// A function to simulate a long-running async operation
function simulateAsyncTask(durationMs) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(`Async task finished after ${durationMs}ms.`);
      resolve();
    }, durationMs);
  });
}

// Helper middleware to check if request has timed out and halt further processing
function haltOnTimedout(req, res, next) {
  if (!req.timedout) {
    next();
  } else {
    console.warn(`Request to ${req.originalUrl} timed out.`);
    // Optionally send a custom response here, or let the error handler catch it
    if (!res.headersSent) {
       res.status(503).send('Service Unavailable: Request timed out.');
    }
  }
}

// Route with a 3-second timeout
app.get('/slow-task', timeout('3s'), haltOnTimedout, async (req, res, next) => {
  try {
    const randomDelay = Math.random() * 5000 + 1000; // 1 to 6 seconds
    console.log(`Starting slow task for ${randomDelay}ms.`);
    await simulateAsyncTask(randomDelay);
    
    // Check if the request has already timed out before sending a response
    if (req.timedout) {
      console.log('Request timed out before sending success response.');
      return; // Do not send response if already timed out
    }

    res.status(200).send('Task completed successfully!');
  } catch (error) {
    next(error);
  }
});

// Error handling middleware for timeout errors
app.use((err, req, res, next) => {
  if (err.timeout) {
    console.error('Request timeout error caught by error handler:', err.message);
    // The `haltOnTimedout` middleware above already handles the response,
    // but this ensures any other timeout scenarios are caught.
    if (!res.headersSent) {
      res.status(503).send('Service Unavailable: Caught by error handler.');
    }
  } else {
    console.error('General error:', err.message);
    if (!res.headersSent) {
      res.status(500).send('Internal Server Error.');
    }
  }
});

const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Server listening on port ${PORT}`);
  console.log('Try accessing http://localhost:3000/slow-task');
});

view raw JSON →