@nxtedition/nxt-undici 6.0.16 → 6.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,8 @@
1
1
  import net from 'node:net'
2
- import { resolve4 } from 'node:dns'
2
+ import assert from 'node:assert'
3
+ import * as dns from 'node:dns'
3
4
  import { DecoratorHandler, getFastNow } from '../utils.js'
4
5
 
5
- const MAX_TTL = 10e3
6
-
7
6
  class Handler extends DecoratorHandler {
8
7
  #callback
9
8
  #statusCode
@@ -37,33 +36,29 @@ export default () => (dispatch) => {
37
36
  const cache = new Map()
38
37
  const promises = new Map()
39
38
 
40
- function resolve(hostname) {
39
+ function resolve(resolve4, hostname) {
41
40
  let promise = promises.get(hostname)
42
41
  if (!promise) {
43
42
  promise = new Promise((resolve) =>
44
43
  resolve4(hostname, { ttl: true }, (err, records) => {
45
- let ret
46
-
47
44
  if (err) {
48
- ret = { error: err }
45
+ resolve([err, null])
49
46
  } else {
50
47
  const now = getFastNow()
51
- ret = {
52
- value: records.map(({ address, ttl }) => ({
53
- address,
54
- expires: now + Math.min(MAX_TTL, 1e3 * ttl),
55
- pending: 0,
56
- errored: 0,
57
- counter: 0,
58
- })),
59
- }
60
- }
48
+ const val = records.map(({ address, ttl }) => ({
49
+ address,
50
+ expires: now + 1e3 * ttl,
51
+ pending: 0,
52
+ errored: 0,
53
+ counter: 0,
54
+ }))
61
55
 
62
- cache.set(hostname, ret)
56
+ cache.set(hostname, val)
63
57
 
64
- promises.delete(hostname)
58
+ resolve([null, val])
59
+ }
65
60
 
66
- resolve(ret)
61
+ assert(promises.delete(hostname))
67
62
  }),
68
63
  )
69
64
  promises.set(hostname, promise)
@@ -87,12 +82,22 @@ export default () => (dispatch) => {
87
82
 
88
83
  const now = getFastNow()
89
84
 
90
- let records = cache.get(hostname)?.value
85
+ let records = cache.get(hostname)
86
+
87
+ const resolve4 = opts.dns.resolve4 || dns.resolve4
91
88
 
92
89
  if (records == null || records.every((x) => x.expires < now)) {
93
- records = await resolve(hostname)
90
+ const [err, val] = await resolve(resolve4, hostname)
91
+
92
+ if (err) {
93
+ throw err
94
+ }
95
+
96
+ assert(val.every((x) => x.expires > 0))
97
+
98
+ records = val
94
99
  } else if (records.some((x) => x.expires < now + 1e3)) {
95
- resolve(hostname)
100
+ resolve(resolve4, hostname)
96
101
  }
97
102
 
98
103
  records.sort(
@@ -1,3 +1,5 @@
1
+ import { once } from 'node:events'
2
+ import http from 'node:http'
1
3
  import { test } from 'tap'
2
4
  import { request } from '../index.js'
3
5
 
@@ -7,3 +9,74 @@ test('retry destroy pre response', async (t) => {
7
9
  t.equal(statusCode, 200)
8
10
  t.end()
9
11
  })
12
+
13
+ test('expire & retry on error', async (t) => {
14
+ t.plan(3)
15
+
16
+ const server = http
17
+ .createServer((req, res) => {
18
+ res.end()
19
+ })
20
+ .listen(0)
21
+ t.teardown(server.close.bind(server))
22
+
23
+ await once(server, 'listening')
24
+
25
+ let counter = 0
26
+ const { body } = await request(`http://asd.com:${server.address().port}`, {
27
+ dns: {
28
+ resolve4(hostname, opts, callback) {
29
+ t.pass()
30
+ if (counter++ === 0) {
31
+ process.nextTick(callback, null, [{ address: '11.9.9.9', ttl: 600 }])
32
+ } else {
33
+ process.nextTick(callback, null, [{ address: '127.0.0.1', ttl: 600 }])
34
+ }
35
+ },
36
+ },
37
+ retry: 2,
38
+ })
39
+ await body.dump()
40
+
41
+ t.pass()
42
+ })
43
+
44
+ test('expire on error', async (t) => {
45
+ t.plan(2)
46
+
47
+ const server = http
48
+ .createServer((req, res) => {
49
+ res.end()
50
+ })
51
+ .listen(0)
52
+ t.teardown(server.close.bind(server))
53
+
54
+ await once(server, 'listening')
55
+
56
+ try {
57
+ const { body } = await request(`http://123.com:${server.address().port}`, {
58
+ dns: {
59
+ resolve4(hostname, opts, callback) {
60
+ process.nextTick(callback, null, [{ address: '10.9.9.9', ttl: 600 }])
61
+ },
62
+ },
63
+ retry: false,
64
+ })
65
+ await body.dump()
66
+ } catch (err) {
67
+ t.equal(err.code, 'UND_ERR_CONNECT_TIMEOUT')
68
+ }
69
+
70
+ const { body } = await request(`http://123.com:${server.address().port}`, {
71
+ dns: {
72
+ resolve4(hostname, opts, callback) {
73
+ process.nextTick(callback, null, [{ address: '127.0.0.1', ttl: 600 }])
74
+ },
75
+ },
76
+ retry: false,
77
+ })
78
+ await body.dump()
79
+
80
+ console.error('### 4')
81
+ t.pass()
82
+ })
package/lib/utils.js CHANGED
@@ -123,6 +123,7 @@ export async function retry(err, retryCount, opts) {
123
123
  'EHOSTDOWN',
124
124
  'EHOSTUNREACH',
125
125
  'EPIPE',
126
+ 'UND_ERR_CONNECT_TIMEOUT',
126
127
  ].includes(err.code)
127
128
  ) {
128
129
  return tp.setTimeout(Math.min(10e3, retryCount * 1e3), undefined, { signal: opts.signal })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/nxt-undici",
3
- "version": "6.0.16",
3
+ "version": "6.0.18",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "main": "lib/index.js",