13

I'm very new to Node.js and I'm having an issue using node.dns.resolveNs function.

Some domains are completely down and it takes about a minute to get the response, which is usually "queryNs ETIMEOUT". Is there a way for me to set it to a shorter period, for example 10 seconds?

Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
Salmon
  • 695
  • 1
  • 11
  • 20
  • searching npm I also found https://github.com/tjfontaine/node-dns which also supports timeouts....? – Alfred May 29 '12 at 02:37
  • Consider this more recent package instead which isn't deprecated: https://github.com/mafintosh/dns-socket – Elad Nava Sep 16 '21 at 15:57

6 Answers6

21

I am not sure of any way to set a timeout directly on the function call, but you could create a small wrapper around the call to handle timing out yourself:

var dns = require('dns');

var nsLookup = function(domain, timeout, callback) {
  var callbackCalled = false;
  var doCallback = function(err, domains) {
    if (callbackCalled) return;
    callbackCalled = true;
    callback(err, domains);
  };

  setTimeout(function() {
    doCallback(new Error("Timeout exceeded"), null);
  }, timeout);

  dns.resolveNs(domain, doCallback);
};

nsLookup('stackoverflow.com', 1000, function(err, addresses) {
  console.log("Results for stackoverflow.com, timeout 1000:");
  if (err) {
    console.log("Err: " + err);
    return;
  }
  console.log(addresses);
});

nsLookup('stackoverflow.com', 1, function(err, addresses) {
  console.log("Results for stackoverflow.com, timeout 1:");
  if (err) {
    console.log("Err: " + err);
    return;
  }
  console.log(addresses);
});

The output for the above script:

Results for stackoverflow.com, timeout 1:
Err: Error: Timeout exceeded
Results for stackoverflow.com, timeout 1000:
[ 'ns1.serverfault.com',
  'ns2.serverfault.com',
  'ns3.serverfault.com' ]
Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
  • Really, I liked it so much, I am adapting it so that the callback can be generic, and it can become a neat way to call any network call with a custom timeout... – Merc Aug 10 '12 at 10:58
  • You have to be careful about the number of concurrent requests (as you don't really timeout them, this is just an emulation). – aymericbeaumet May 13 '15 at 08:59
17

Node.js dns.resolve* use c-ares library underneath, which supports timeouts and various other options natively. Unfortunately Node.js doesn't expose those tunables, but some of them can be set via RES_OPTIONS environment variable.

Example: RES_OPTIONS='ndots:3 retrans:1000 retry:3 rotate' node server.js

  • ndots: same as ARES_OPT_NDOTS
  • retrans: same as ARES_OPT_TIMEOUTMS
  • retry: same as ARES_OPT_TRIES
  • rotate: same as ARES_OPT_ROTATE

See man ares_init_options(3) for details what each option means, for instance here http://manpages.ubuntu.com/manpages/zesty/man3/ares_init_options.3.html

redbaron
  • 398
  • 3
  • 11
  • 3
    This should be marked as the best answer IMO. Thank you @redbaron! Tuning this parameters have reduced my AWS lambda execution time from ~5 minutes to 30 seconds. – Pavel K Jan 07 '19 at 09:34
  • 1
    Now its possible to set timeout and tries. https://nodejs.org/api/dns.html#resolveroptions – Zoltán Hajdú Apr 11 '22 at 20:11
  • It seems this env var can affect more than just dns.resolve - I tried setting it to reduce occasional DNS timeouts and found that it prevented my app from connecting to MongoDB successfully. Use with care. – stephent May 13 '22 at 15:25
1

Also it good to know that lookup may block your application.

We developed a module that replaces/extends node's dns.lookup method. The main goal is to bypass issues with blocking of thread pool. So module caches responses, has multi-records resolving and TTL support. Also we have good unit and functional tests with 100% coverage. Module was tested in production and highload environments. Under MIT license.

Here it is: https://github.com/LCMApps/dns-lookup-cache

I believe it may help!

WoZ
  • 152
  • 1
  • 7
0

building upon @redbaron's answer, you can set the RES_OPTIONS variable during runtime to set the timeout for the c-ares library used by dns.resolve*:

// this will timeout for (1000 * 3 * 2) ms
process.env.RES_OPTIONS='ndots:3 retrans:1000 retry:3 rotate';
Binary
  • 451
  • 5
  • 15
0

Wrapper for resolveNs with timeout:

const dns = require("dns");

const nsLookup = (domain, timeout) => {
  return new Promise((resolve, reject) => {
    let finished = false;

    const timer = setTimeout(()=>{
      finished = true; 
      reject();
    }, timeout);

    const callback = (_err, result) => {
      clearTimeout(timer);
      if (!finished) resolve(result);
    };
  
    dns.resolveNs(domain, callback);  
  });
};
chickens
  • 19,976
  • 6
  • 58
  • 55
0

Use the Resolver object, which takes a timeout params in it's constructor args...

e.g.

const { Resolver }= require('dns').promises;

const yourTimeout = 5000; // milliseconds

const resolver = new Resolver({timeout: yourTimeout});

const response = await resolver.resolve('www.google.com');