Skip to content
This repository has been archived by the owner on Feb 8, 2023. It is now read-only.

feat: support lookup with timeout #1

Merged
merged 3 commits into from
Sep 27, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
sudo: false
language: node_js
node_js:
- 6
- 4
- '6'
- '4'
script:
- npm run ci
after_script:
Expand Down
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ failover-dns

Use local cache dns query result when dns query fail.

- Support dns lookup with `options.timeout`.

## Installation

```bash
Expand All @@ -37,12 +39,26 @@ const dns = require('failover-dns');
// must listen `error` event to logging by yourself
dns.on('error', err => console.error(err));

dns.lookup('cnpmjs.org', { family: 4 }, (err, ip, family) => {
dns.lookup('cnpmjs.org', { family: 4, timeout: 2000 }, (err, ip, family) => {
if (err) throw err;
console.log(ip, family);
});
```

## Default dns query timeout

Default is `0`:

```js
exports.defaultTimeout = 0;
```

Maybe you want to set global default timeout is `2000ms`:

```js
exports.defaultTimeout = 2000;
```

## License

[MIT](LICENSE)
40 changes: 37 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,28 @@ module.exports = exports = new EventEmitter();

exports.DNS_LOOKUP_CACHE = DNS_LOOKUP_CACHE;

// you can set global timeout, default is 0
exports.defaultTimeout = 0;

exports.lookup = function lookup(hostname, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
options = null;
}
options = options || {};
options.timeout = options.timeout || exports.defaultTimeout;

// don't failover on `options.all = true`
if (options.all) {
// don't failover on options.all
return dns.lookup(hostname, options, callback);
}

const cacheKey = `${hostname}_${options.family}_${options.hints}`;
dns.lookup(hostname, options, (err, ip, family) => {
exports._lookupWithTimeout(hostname, options, (err, ip, family) => {
if (err) {
if (err.name === 'Error') {
err.name = 'DNSLookupError';
}
const address = DNS_LOOKUP_CACHE[cacheKey];
if (address) {
// emit error event for logging
Expand Down Expand Up @@ -49,3 +58,28 @@ exports.lookup = function lookup(hostname, options, callback) {
callback(null, ip, family);
});
};

exports._lookupWithTimeout = function lookupWithTimeout(hostname, options, callback) {
if (!options.timeout) {
return dns.lookup(hostname, options, callback);
}

let timer = setTimeout(() => {
timer = null;
const cb = callback;
callback = null;
const err = new Error(`getaddrinfo TIMEOUT ${hostname}`);
err.name = 'DNSLookupTimeoutError';
err.options = options;
err.code = 'TIMEOUT';
cb(err);
}, options.timeout);

dns.lookup(hostname, options, (err, ip, family) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

没想到竟然还不支持 timeout 。。。

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

额,原生不支持。。。

timer && clearTimeout(timer);
if (!callback) {
return;
}
callback(err, ip, family);
});
};
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"index.js"
],
"scripts": {
"test": "npm run lint && mocha -t 5000 -r intelli-espower-loader test/*.test.js",
"test-cov": "istanbul cover _mocha -- -t 5000 -r intelli-espower-loader test/*.test.js",
"test": "npm run lint && mocha -t 15000 -r intelli-espower-loader test/*.test.js",
"test-cov": "istanbul cover _mocha -- -t 15000 -r intelli-espower-loader test/*.test.js",
"lint": "eslint test *.js",
"ci": "npm run lint && npm run test-cov",
"autod": "autod -w --prefix '^'"
Expand Down
64 changes: 64 additions & 0 deletions test/failover-dns.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,26 @@ describe('test/failover-dns.test.js', () => {
});
});

it('should lookup with options=null from dns server', done => {
dns.lookup('a.alipayobjects.com', null, (err, ip, family) => {
console.log(err, ip, family);
assert(err == null);
assert((/^\d+\.\d+\.\d+\.\d+$/).test(ip));
assert(family === 4);
done();
});
});

it('should lookup with options.timeout', done => {
dns.lookup('as.alipayobjects.com', { timeout: 5000 }, (err, ip, family) => {
console.log(err, ip, family);
assert(err == null);
assert((/^\d+\.\d+\.\d+\.\d+$/).test(ip));
assert(family === 4);
done();
});
});

it('should lookup with options.family from dns server', done => {
dns.lookup('cnpmjs.org', { family: 4 }, (err, ip, family) => {
console.log(err, ip, family);
Expand Down Expand Up @@ -66,6 +86,48 @@ describe('test/failover-dns.test.js', () => {
});
});

it('should mock timeout then return address from local cache', done => {
done = pedding(2, done);
mm(require('dns'), 'lookup', (hostname, options, callback) => {
setTimeout(() => {
callback(null, '127.0.0.1', 4);
}, 600);
});

dns.once('error', err => {
console.log(err);
assert(err.name === 'DNSLookupTimeoutError');
assert(err.message === 'getaddrinfo TIMEOUT a.alipayobjects.com');
done();
});
dns.lookup('a.alipayobjects.com', { family: 4, timeout: 500 }, (err, ip, family) => {
console.log('lookup result', err, ip, family);
assert(err == null);
assert((/^\d+\.\d+\.\d+\.\d+$/).test(ip));
assert(family === 4);
// wait for dns.lookup() done and ignore callback
setTimeout(done, 200);
});
});

it('should mock timeout and local cache missing', done => {
mm(require('dns'), 'lookup', (hostname, options, callback) => {
setTimeout(() => {
callback(null, '127.0.0.1', 4);
}, 600);
});

dns.lookup('foo.cnpmjs.org', { family: 4, timeout: 500 }, (err, ip, family) => {
console.log('lookup result', err, ip, family);
assert(err);
assert(err.name === 'DNSLookupTimeoutError');
assert(err.message === 'getaddrinfo TIMEOUT foo.cnpmjs.org');
assert(err.code === 'TIMEOUT');
// wait for dns.lookup() done and ignore callback
setTimeout(done, 200);
});
});

it('should lookup with options.all from dns server', done => {
dns.lookup('a.alipayobjects.com', { all: true }, (err, ips) => {
console.log(err, ips);
Expand All @@ -80,6 +142,8 @@ describe('test/failover-dns.test.js', () => {
dns.lookup('cnpmjs.org', { family: 6 }, (err, ip, family) => {
console.log(err, ip, family);
assert(err);
assert(err.name === 'DNSLookupError');
assert(err.message === 'getaddrinfo ENOTFOUND cnpmjs.org');
done();
});
});
Expand Down