-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
Expose Undici's ProxyAgent and setGlobalDispatcher within Node #43187
Comments
global[Symbol.for('undici.globalDispatcher.1')] = yourDispatcher; |
Replying to the last comment from @mcollina in the previous issue:
This makes sense! I'm not aware of Undici's process around stability guarantees like this, but I can understand how there are constraints there. I do understand this isn't a top top priority since installing & importing Undici elsewhere is a usable workaround, so there's certainly no rush just would justify shipping an unstable API unnecessarily. I do think that the current situation isn't a good end state though, and there are good options we can aim for to fix this, so it would be great to find agreement to aim in that direction in the medium term. I'm not sure how to take anything to the TSC, but very happy to be included on any discussion of this any time. |
That's does work as a workaround, but it's not especially nice as the official API for this, and I think ProxyAgent needs to be available too to make this usable for global Fetch. |
I don't think we should expose |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
2022-11-14, Version 19.1.0
|
That does not mark it stable, on purpose. It's the first step on that journey. This is something we might want to consider right now. |
In the TSC meeeting of today, we decided that we are going to support HTTP_PROXY, HTTPS_PROXY and NO_PROXY env variables directly in Undici: nodejs/undici#1650. |
How is it going to handle different casing rules? |
At a minimum, I'd love it if I could use the workaround without calling |
Setting the proxy relies on undici for now undici does not respect the HTTP_PROXY vars, it's planned to build it in from v23 on by default: nodejs/node#43187 (comment) > My current plan is to add support for the HTTP_PROXY env variable behind a flag in v22 (and possibly v20), then unflag in v23. Using global dispatcher is the current way to go for native fetch, therefore undici needs to be added. For connectrpc the agent will be passed down the chain: /** * Options passed to the request() call of the Node.js built-in * http or https module. * example proxy trace: 22:05:23 HTTPS POST localhost/auth/realms/cosmo/protocol/openid-connect/token 200 application/json 2.0k 202ms 22:05:35 HTTP POST localhost/wg.cosmo.platform.v1.PlatformService/DeleteFederatedGraph 200 application/proto 44b 64ms
Setting the proxy relies on undici for now undici does not respect the HTTP_PROXY vars, it's planned to build it in from v23 on by default: nodejs/node#43187 (comment) > My current plan is to add support for the HTTP_PROXY env variable behind a flag in v22 (and possibly v20), then unflag in v23. Using global dispatcher is the current way to go for native fetch, therefore undici needs to be added. For connectrpc the agent will be passed down the chain: /** * Options passed to the request() call of the Node.js built-in * http or https module. * example proxy trace: 22:05:23 HTTPS POST localhost/auth/realms/cosmo/protocol/openid-connect/token 200 application/json 2.0k 202ms 22:05:35 HTTP POST localhost/wg.cosmo.platform.v1.PlatformService/DeleteFederatedGraph 200 application/proto 44b 64ms
The easiest way is to pass { dispatcher: x } on each undici call, otherwise there is a factory method if using a global dispatcher. Below accesses the internals of undici to get Agent, the factory method uses either Pool, or Client. /**
* Use the undici internals shipped with Node.js
*/
function getUndiciInternals() {
/* We need to call fetch for the globalDispatcher to be available */
fetch().catch(() => {})
const globalDispatcherSymbol = Symbol.for('undici.globalDispatcher.1')
const agent = globalThis[globalDispatcherSymbol]
/* get access to the factory to avoid needing to reference Pool, and Client */
const agentFactorySymbol = Object.getOwnPropertySymbols(agent).find((x) => x.toString() === 'Symbol(factory)')
const agentFactory = agent[agentFactorySymbol]
const Agent = agent.constructor
return {
globalDispatcherSymbol,
Agent,
agentFactory,
}
}
class MyDispatcher extends undici.Agent {
constructor(options) {
super({
...options,
factory(url, options_) {
// can pass other options here too :)
return undici.agentFactory(url, options_)
},
})
}
}
globalThis[undici.globalDispatcherSymbol] = new MyDispatcher() |
@nodejs/tsc I think we need to make a decision here. Do we want to expose the bundled undici or not? Even if not, we should at least provide some API to get the undici Agent because people are doing all kind of hacks to get it. |
Press 👍🏻 if you think Undici should be exposed and 👎🏻 if not |
Developers try to find a solution to their problem. We can call it hack. This is why I suggested to expose the whole undici ~1 year ago. |
Would be nice to expose using |
I like the idea of exporting |
When fetching things during postinstall, add a much shorter timeout to ensure things keep progressing. If nodejs/node/issues/43187 gets resolved, we may be able to switch to importing `node:undici` instead of adding another copy with possibly incompatible API. Signed-off-by: Mark Yen <mark.yen@suse.com>
When fetching things during postinstall, add a much shorter timeout to ensure things keep progressing. If nodejs/node/issues/43187 gets resolved, we may be able to switch to importing `node:undici` instead of adding another copy with possibly incompatible API. Signed-off-by: Mark Yen <mark.yen@suse.com>
When fetching things during postinstall, actually retry downloads if they fail partway through. If nodejs/node/issues/43187 gets resolved, we may be able to switch to importing `node:undici` instead of adding another copy with possibly incompatible API. Signed-off-by: Mark Yen <mark.yen@suse.com>
When fetching things during postinstall, actually retry downloads if they fail partway through. If nodejs/node/issues/43187 gets resolved, we may be able to switch to importing `node:undici` instead of adding another copy with possibly incompatible API. Signed-off-by: Mark Yen <mark.yen@suse.com>
When fetching things during postinstall, actually retry downloads if they fail partway through. If nodejs/node/issues/43187 gets resolved, we may be able to switch to importing `node:undici` instead of adding another copy with possibly incompatible API. Signed-off-by: Mark Yen <mark.yen@suse.com>
When fetching things during postinstall, actually retry downloads if they fail partway through. If nodejs/node/issues/43187 gets resolved, we may be able to switch to importing `node:undici` instead of adding another copy with possibly incompatible API. Signed-off-by: Mark Yen <mark.yen@suse.com>
9/4 Meeting
9/11 Meeting
|
Any more background on this? |
What about exposing normal |
We wound up going down the path of including undici directly for most of what we're doing (using request and overriding the global dispatcher to use a custom lookup function) With Node 22 including the web socket implementation, we went ahead and preemptively switched to that on Node 20 as well. Having to include it manually isn't that big of a deal as long as it plays nicely together (i.e.: not needing to set 2 "global" dispatchers to cover anything that feeds through the native fetch). |
Sooo is it happening? |
@JakobJingleheimer it needs a champion. |
Fetch in node.js is powered by undici, node requires undici when fetch is called the first time: let fetchImpl; // https://fetch.spec.whatwg.org/#fetch-method ObjectDefineProperty(globalThis, 'fetch', { __proto__: null, configurable: true, enumerable: true, writable: true, value: function fetch(input, init = undefined) { // eslint-disable-line func-name-matching if (!fetchImpl) { // Implement lazy loading of undici module for fetch function const undiciModule = require('internal/deps/undici/undici'); fetchImpl = undiciModule.fetch; } return fetchImpl(input, init); }, }); Only then will setGlobalDispatcher be available (albeit via a symbol hack) We need to wait until setGlobalDispatcher is properly exposed: nodejs/node#43187 We be able to call setGlobalDispatcher immediately, we call `fetch` with an arguments and catch the error. We also need to wrap the fetch(<NO ARGS>) call itself, even though there's `.catch(...)`. This is because dd-trace throws an invalid URL error.
Originally posted by @pimterry in #42814 (comment)
The text was updated successfully, but these errors were encountered: