javascript - Why can ClientRequest.setTimeout take much longer than the provided duration? - Stack Overflow

In the following nodejs program, I am patching the dns.lookup function in order to investigate how a sl

In the following nodejs program, I am patching the dns.lookup function in order to investigate how a slow DNS lookup would behave when a timeout is set on a request. The DNS lookup will (appear to) take 10 seconds, so I expect my 1000ms timeout on the request to be triggered.

My timeout on the request is indeed triggered, but after around 5000ms instead of 1000ms as expected. Why could this be?

const dns = require('dns');
const http = require('http');
const lookup = dns.lookup;

const now = Date.now();

// I'm trying to simulate a slow DNS lookup here, to test how it behaves with the various nodejs
// timeout options.
dns.lookup = function patchedLookup(...args) {
  setTimeout(() => {
    lookup.apply(this, args);
  }, 10_000);
};

const req = http.request('');

// The slow DNS lookup should cause this to timeout after 1000ms.
req.setTimeout(1000, () => {
  // Logs something like "timed out after 5007ms" - why not after 1000ms?
  console.error(`timed out after ${Date.now() - now}ms`);
  req.abort();
});

req.on('error', (err) => {
  console.error(`error after ${Date.now() - now}ms: ${err}`);
});

req.end();

In the following nodejs program, I am patching the dns.lookup function in order to investigate how a slow DNS lookup would behave when a timeout is set on a request. The DNS lookup will (appear to) take 10 seconds, so I expect my 1000ms timeout on the request to be triggered.

My timeout on the request is indeed triggered, but after around 5000ms instead of 1000ms as expected. Why could this be?

const dns = require('dns');
const http = require('http');
const lookup = dns.lookup;

const now = Date.now();

// I'm trying to simulate a slow DNS lookup here, to test how it behaves with the various nodejs
// timeout options.
dns.lookup = function patchedLookup(...args) {
  setTimeout(() => {
    lookup.apply(this, args);
  }, 10_000);
};

const req = http.request('http://joebarnett.xyz');

// The slow DNS lookup should cause this to timeout after 1000ms.
req.setTimeout(1000, () => {
  // Logs something like "timed out after 5007ms" - why not after 1000ms?
  console.error(`timed out after ${Date.now() - now}ms`);
  req.abort();
});

req.on('error', (err) => {
  console.error(`error after ${Date.now() - now}ms: ${err}`);
});

req.end();

Share Improve this question asked Mar 25 at 20:15 dipeadipea 5831 gold badge5 silver badges23 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

The req.setTimeout() timeout only starts being enforced after a socket is assigned to the request. If the request is still in the DNS resolution phase, the timeout will not be triggered until after the DNS lookup completes and a socket is assigned.

To enforce a total timeout, including DNS resolution, you can use a separate timer to wrap the entire request operation, including DNS resolution.

const dns = require('dns');
const http = require('http');
const lookup = dns.lookup;

const now = Date.now();

dns.lookup = function patchedLookup(...args) {
  setTimeout(() => {
    lookup.apply(this, args);
  }, 10_000);
};

const globalTimeout = 1000;
const timer = setTimeout(() => {
  console.error(`Global timeout after ${Date.now() - now}ms`);
  req.abort();
}, globalTimeout);

const req = http.request('http://joebarnett.xyz', () => {
  clearTimeout(timer);
});

req.setTimeout(globalTimeout, () => {
  console.error(`Request timed out after ${Date.now() - now}ms`);
  req.abort();
});

req.on('error', (err) => {
  clearTimeout(timer);
  console.error(`Error after ${Date.now() - now}ms: ${err}`);
});

This ensures the timeout applies to the entire lifecycle of the request, including DNS resolution.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744170852a4561527.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信