@nxtedition/nxt-undici 7.3.19 → 7.3.20

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.
@@ -52,7 +52,6 @@ export default () => (dispatch) => {
52
52
  pending: 0,
53
53
  errored: 0,
54
54
  counter: 0,
55
- timeout: 0,
56
55
  }
57
56
  })
58
57
 
@@ -68,35 +67,31 @@ export default () => (dispatch) => {
68
67
  }
69
68
 
70
69
  return async (opts, handler) => {
71
- if (!opts.dns || !opts.origin) {
72
- return dispatch(opts, handler)
73
- }
70
+ try {
71
+ if (!opts.dns || !opts.origin) {
72
+ return dispatch(opts, handler)
73
+ }
74
74
 
75
- const ttl = opts.dns.ttl ?? 2e3
76
- const url = new URL(opts.path ?? '', opts.origin)
77
- const balance = opts.dns.balance
75
+ const ttl = opts.dns.ttl ?? 2e3
76
+ const url = new URL(opts.path ?? '', opts.origin)
77
+ const balance = opts.dns.balance
78
78
 
79
- const { host, hostname, pathname } = url
79
+ const { host, hostname, pathname } = url
80
80
 
81
- if (net.isIP(hostname)) {
82
- return dispatch(opts, handler)
83
- }
81
+ if (net.isIP(hostname)) {
82
+ return dispatch(opts, handler)
83
+ }
84
84
 
85
- try {
86
85
  const now = getFastNow()
87
86
 
88
87
  let records = cache.get(hostname)
89
88
 
90
89
  if (records == null || records.every((x) => x.expires < now)) {
91
90
  const [err, val] = await resolve(hostname, { ttl })
92
-
93
91
  if (err) {
94
92
  throw err
95
93
  }
96
-
97
94
  records = val
98
- } else if (records.some((x) => x.expires < now + 1e3)) {
99
- resolve(hostname, { ttl })
100
95
  }
101
96
 
102
97
  let record
@@ -108,7 +103,7 @@ export default () => (dispatch) => {
108
103
 
109
104
  for (let i = 0; i < records.length; i++) {
110
105
  const idx = (hash + i) % records.length
111
- if (records[idx].expires >= now && records[idx].timeout < now) {
106
+ if (records[idx].expires >= now) {
112
107
  record = records[idx]
113
108
  break
114
109
  }
@@ -116,13 +111,14 @@ export default () => (dispatch) => {
116
111
  }
117
112
 
118
113
  if (record == null) {
119
- records.sort(
114
+ // toSorted — balance:'hash' relies on the cached array's index order.
115
+ const sorted = records.toSorted(
120
116
  (a, b) => a.errored - b.errored || a.pending - b.pending || a.counter - b.counter,
121
117
  )
122
118
 
123
- for (let i = 0; i < records.length; i++) {
124
- if (records[i].expires >= now && records[i].timeout < now) {
125
- record = records[i]
119
+ for (let i = 0; i < sorted.length; i++) {
120
+ if (sorted[i].expires >= now) {
121
+ record = sorted[i]
126
122
  break
127
123
  }
128
124
  }
@@ -135,7 +131,15 @@ export default () => (dispatch) => {
135
131
  })
136
132
  }
137
133
 
138
- url.hostname = record.address
134
+ // Pre-emptive refresh when any record is past half its TTL — the
135
+ // in-flight request still uses the already-selected `record`; the
136
+ // refreshed records land in cache for the next request, smoothing
137
+ // out DNS lookup latency. `resolve()` dedupes via `promises`.
138
+ if (records.some((x) => x.expires < now + ttl / 2)) {
139
+ resolve(hostname, { ttl })
140
+ }
141
+
142
+ url.hostname = net.isIPv6(record.address) ? `[${record.address}]` : record.address
139
143
 
140
144
  record.counter++
141
145
  record.pending++
@@ -150,10 +154,6 @@ export default () => (dispatch) => {
150
154
  } else if (statusCode != null && statusCode >= 500) {
151
155
  record.errored++
152
156
  }
153
-
154
- if (err != null || statusCode >= 500) {
155
- record.timeout = getFastNow() + 10e3
156
- }
157
157
  }),
158
158
  )
159
159
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/nxt-undici",
3
- "version": "7.3.19",
3
+ "version": "7.3.20",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "main": "lib/index.js",