-
-
Notifications
You must be signed in to change notification settings - Fork 688
feat(interceptors/dns): cache option #4565
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Uzlopak
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So you just renamed the attribute records to cache. Made the attribute public. And lastly you make the cache as an option to be passed via the options parameter of the constructor.
I have questions:
Why is cache now publicly accessible? Did you do this on purpose? Please explain.
What happens if i pass an lru cache which handles ttl and max items by itself. How is full coming into play with this if the LRU cache is configured with other values?
In runLookup we just ignore new entries if the Map is full. Isnt the point of having an LRU, to have the last recently used element be in the cache and not the first x elements till hitting the maxItems limit?
There is no definition of the shape of the cache. What if a .get() call returns undefined and not null?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds a configurable cache option to the DNS interceptor, allowing users to provide custom cache implementations instead of being limited to the default Map. This enables custom metrics for DNS cache hit rate monitoring and support for specialized cache libraries like lru-cache.
Key changes:
- Added
cacheparameter toDNSInstanceconstructor with Map as default fallback - Replaced all internal
#recordsMap usage with the configurablecacheproperty
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| affinity = null | ||
| lookup = null | ||
| pick = null | ||
| cache = null |
Copilot
AI
Sep 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cache property should not be initialized to null since it's expected to be a Map-like object. Consider initializing it to new Map() or removing the initialization entirely since it's set in the constructor.
| cache = null |
lib/interceptor/dns.js
Outdated
| this.cache = opts.cache ?? new Map() | ||
| } |
Copilot
AI
Sep 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing input validation for the cache parameter. The cache object should be validated to ensure it has the required Map-like interface (get, set, delete, size properties/methods) before assignment to prevent runtime errors.
| this.cache = opts.cache ?? new Map() | |
| } | |
| if (opts.cache !== undefined && opts.cache !== null) { | |
| if ( | |
| typeof opts.cache.get !== 'function' || | |
| typeof opts.cache.set !== 'function' || | |
| typeof opts.cache.delete !== 'function' || | |
| (typeof opts.cache.size !== 'number' && typeof opts.cache.size !== 'undefined') | |
| ) { | |
| throw new InvalidArgumentError('cache must implement the Map interface (get, set, delete methods and size property)') | |
| } | |
| this.cache = opts.cache | |
| } else { | |
| this.cache = new Map() | |
| } |
|
Hi! Thanks for the quick response.
I made
At first, I think that cache ttl and size is a bit out of scope of interceptor, and in the future this logic can be incapsulated in some default cache implementation. But for now, if
Yes, and because of that LRU cache can be more effective. But it is just an example, I'm not sure that applications have so many hosts for resolution that you need to worry about cache size. DNS cache is more about balance between requests speed and failure rate because of outdated ips. So custom cache metrics can be really useful here to fine tuning.
Can we do here something without TypeScript? Maybe I can define interface with JSdoc |
|
I think the interceptor was planned with integrated cache. Infinity as default values is not acceptable, because it would be a source for a memory leak. I really think, that you need to either extract the caching logic properly or it is imho not acceptable. |
|
Agree with @Uzlopak in the term of extracting the We need to set an explicit contract the passed Abstracting the current
|
|
Maybe we should also avoid the word Cache. Maybe we should use the word Store? Or cache-store? :/ |
|
100% agreed with cache extraction, will be back soon |
|
And another idea - we can just integrate diagnostic channel for monitoring purposes |
|
Demo with extracted cache - 6605718 Extracted cache have so much logic to handle TTL at IP records level, and looking at it, I no longer think the decision is such a good idea. Maybe we need just a simple Map-like API for cache and use this cache exclusively as storage. But this brings us back to decide how this will be combined with ttl at the lru-cache level - I think Also, |
| } | ||
|
|
||
| // TODO: it will require to write adapter for different caches, look for a better ideas | ||
| get full () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incompatible with js Map interface
metcoder95
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we need just a simple Map-like API for cache and use this cache exclusively as storage.
This was the exact suggestion from @Uzlopak, let's follow that path; and if seeking for compatibility with lru-cache-like solutions, we can hint the recommendations for making it compatible with the DNSStorage interface.
| const maxInt = Math.pow(2, 31) - 1 | ||
|
|
||
| class DNSInstance { | ||
| export class DNSCache { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| export class DNSCache { | |
| export class DNSStore { |
As @Uzlopak suggestion 😛
Thanks, I get it too late) Is this solution will be more appropriate? |
metcoder95
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add some tests to cover the new DNSStore feature?
| return this.#records.size | ||
| } | ||
|
|
||
| // TODO: it will require to write adapter for different caches, look for a better ideas |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall we remove the TODO?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before changes, can you please help me to choose between DNSStorage implementations:
- current implementation with incapsulated TTL logic inside storage (have a serious doubts against it as described in feat(interceptors/dns): cache option #4565 (comment))
- simple implementation, only storage logic extracted - https://github.com/nodejs/undici/pull/4589/files
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
simple implementation, only storage logic extracted - #4589 (files)
I'd prefer this one, is simpler and with the example you shared can be enough for implementers to adapt it to their needs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thans, #4589 is ready to review!
| } | ||
| } | ||
|
|
||
| // TODO: deduplicate logic |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall we abstract it then?
| } | ||
| } | ||
|
|
||
| // TODO: deduplicate logic |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
|
Closed in favour of #4589 |
Rationale
Custom
cachefor DNS interceptor allows:lru-cache, etc.)Reference - https://github.com/szmarczak/cacheable-lookup?tab=readme-ov-file#cache
If these changes are acceptable, I will add unit test and validation for this parameter.
Changes
Added
cacheparameter forDNSInstanceStatus