Skip to content

fix(dns): share in-flight lookups between concurrent requests - #5975

Open
ump45nose wants to merge 3 commits into
nodejs:mainfrom
ump45nose:fix/5974-dns-dedupe-lookups
Open

ump45nose wants to merge 3 commits into
nodejs:mainfrom
ump45nose:fix/5974-dns-dedupe-lookups

Conversation

@ump45nose

Copy link
Copy Markdown
Contributor

This relates to...

Fixes #5974

Rationale

When the DNS interceptor has no usable records for a hostname (cold cache, or every cached record has expired), each request starts its own lookup(). A burst of concurrent requests to the same host therefore produces a burst of identical lookups; the reproduction in #5974 sees 100 lookups for 100 concurrent requests.

Changes

Bug Fixes

  • lib/interceptor/dns.js: DNSInstance keeps a per-hostname list of callbacks waiting on an in-flight lookup. Requests that arrive while a lookup for the same hostname is pending join it instead of starting another one. When the lookup completes the records are stored once and each waiting request still runs pick() with its own origin (so ports/protocols are preserved and round-robin keeps working). A failed lookup rejects every waiting request and the pending entry is removed, so the next request retries.
  • Requests that pass per-request dns options (opts.dns) keep their own lookup, since they may resolve differently.
  • docs/docs/api/Interceptors.md: one sentence describing the shared in-flight lookup.
  • test/interceptors/dns.js: two regression tests — 20 concurrent requests share one lookup and a second batch uses the cache; 5 concurrent requests sharing a failed lookup all reject with ENOTFOUND, and the following request performs a fresh lookup.

Features

N/A

Breaking Changes and Deprecations

N/A

Testing (Node.js v22.20.0, Linux)

  • node --test --test-name-pattern='#5974' test/interceptors/dns.js: 2/2 pass with the fix; both fail on unmodified main (20 lookups instead of 1; not all requests rejected by the failed lookup).
  • The standalone script from DNS interceptor does not deduplicate concurrent lookups for the same hostname #5974: { coldCacheLookups: 1, warmCacheLookups: 0 } with the fix, { coldCacheLookups: 100, warmCacheLookups: 0 } on main.
  • node --test test/interceptors/dns.js: of 37 tests, 33 pass (including the two new ones), 3 are skipped because IPv6 localhost is unavailable here, and 1 fails: Should respect DNS origin hostname for SNI on TLS, with ERR_SSL_SSL/TLS_ALERT_HANDSHAKE_FAILURE; it fails the same way on unmodified main, and leaves the run hanging until my 600 s timeout. I'm relying on CI for that one.
  • node --test test/interceptors/origin-isolation.js test/interceptors/deduplicate.js: 73/73 pass.
  • npx eslint lib/interceptor/dns.js test/interceptors/dns.js: clean.

Status

AI assistance was used to help prepare and verify this change.

Requests for the same hostname that arrive while a lookup is still in
flight now wait for that lookup instead of starting their own, so a cold
or expired cache no longer triggers a burst of identical lookups. Each
waiting request still picks its own address from the cached records. A
failed lookup rejects every waiting request and is not left pending, so
the next request retries it. Requests with per-request `dns` options keep
their own lookup.

Fixes nodejs#5974

Signed-off-by: ump45nose <52391318+ump45nose@users.noreply.github.com>
@codecov-commenter

codecov-commenter commented Oct 8, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.36364% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.55%. Comparing base (e960331) to head (e1ad131).

Files with missing lines Patch % Lines
lib/interceptor/dns.js 96.36% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5975      +/-   ##
==========================================
+ Coverage   91.53%   91.55%   +0.01%     
==========================================
  Files         113      113              
  Lines       43597    43623      +26     
==========================================
+ Hits        39908    39937      +29     
+ Misses       3689     3686       -3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@metcoder95 metcoder95 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

@ump45nose

Copy link
Copy Markdown
Contributor Author

Merged latest main into this branch (tip e1ad1311) so CI re-runs against current HEAD, including the recent cache fixes from #5980.

Previous run was green on Node 22/24/25/26 aside from one likely-unrelated flake in test/interceptors/cache.js (stale-while-revalidate updates cache after background revalidation, Node 25 --without-intl). Local #5974 DNS interceptor tests still pass (2/2).

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DNS interceptor does not deduplicate concurrent lookups for the same hostname

3 participants