fix(core): keep Node's global proxy dispatcher when loading undici@8 by dvd233 · Pull Request #1171 · TencentCloud/TencentDB-Agent-Memory · GitHub
Skip to content

fix(core): keep Node's global proxy dispatcher when loading undici@8 - #1171

Open
dvd233 wants to merge 3 commits into
TencentCloud:feat/server_teamfrom
dvd233:fix/tcvdb-undici-global-dispatcher
Open

dvd233 wants to merge 3 commits into
TencentCloud:feat/server_teamfrom
dvd233:fix/tcvdb-undici-global-dispatcher

Conversation

@dvd233

@dvd233 dvd233 commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor

Description | 描述

Fixes #1157. Importing the TCVDB client must not overwrite the legacy global dispatcher used by Node's built-in fetch, including a configured proxy dispatcher.

Load undici lazily on the first TCVDB request, using synchronous CommonJS loading to keep the dispatcher snapshot and restoration in one turn. This also avoids restoring a stale snapshot over a concurrent dispatcher replacement. Construction remains free of undici's global initialization side effects; the TCVDB request/HTTPS-agent behavior remains with the existing client.

Verification | 验证

  • Node 22.22.3: all four focused tests passed, including two fresh-process/cold-cache cases and a real local HTTP round trip.
  • The plugin bundle and migration/export/read script builds succeeded. Full npm run build is not passing: build:seed-v2 reports TS5058 because scripts/seed-v2/tsconfig.json is missing. Running the complete build at the original PR head reproduced the same failure; the package scripts and missing path are unchanged by this PR.
  • The staged and committed follow-up diff matches the reviewed patch byte for byte.

DCO | 签署

The author confirmed the DCO submission rights and authorized correcting the two existing commits. Their code trees, author/committer metadata, and upstream parent are unchanged; only their own DCO trailers and the necessarily regenerated merge signature changed. The follow-up commit also carries the author's sign-off. Recovery refs retain the original commits.

Prepared and verified with Codex assistance. Automated verification does not replace maintainer review or establish official CI success.

undici@8 eagerly calls setGlobalDispatcher(new Agent()) at module load
when Symbol.for("undici.globalDispatcher.2") is unset, overwriting the
legacy Symbol.for("undici.globalDispatcher.1") slot that Node's built-in
fetch reads. With NODE_USE_ENV_PROXY=1, that slot holds Node's
EnvHttpProxyAgent, so importing the TCVDB client silently disabled
HTTP(S)_PROXY for every fetch in the process (L1/Skill extraction then
fail with "Cannot connect to API").

Load undici lazily on first request instead of at module scope, and
snapshot/restore the legacy dispatcher slot across the import so a
pre-configured dispatcher survives. The HTTPS custom-CA Agent creation
moves to the same lazy path, keeping construction side-effect free.

Add regression tests covering both the import side effect and a full
request round-trip against a local HTTP server.

Fixes TencentCloud#1157

Signed-off-by: dvd233 <111864431+dvd233@users.noreply.github.com>
@Maxwell-Code07

Copy link
Copy Markdown
Collaborator

Signed-off-by: dvd233 <111864431+dvd233@users.noreply.github.com>
@kvnloo

kvnloo commented Sep 27, 2026

Copy link
Copy Markdown

Thanks @dvd233 — lazy-loading "undici" looks like a good way to remove the SQLite-mode side effect.

I noticed one concurrency edge in the snapshot/restore guard:

const previousLegacy = g[LEGACY_GLOBAL_DISPATCHER];

undiciModulePromise = import("undici").then((mod) => {
if (
previousLegacy !== undefined &&
g[LEGACY_GLOBAL_DISPATCHER] !== previousLegacy
) {
g[LEGACY_GLOBAL_DISPATCHER] = previousLegacy;
}
return mod;
});

This assumes every change to the legacy slot while "import("undici")" is pending came from undici.

A possible interleaving is:

  1. dispatcher A is installed;
  2. "loadUndici()" snapshots A;
  3. another subsystem intentionally installs dispatcher B;
  4. the dynamic import resolves;
  5. the guard sees "B !== A" and restores A.

So the fix can itself overwrite a newer process-wide networking decision.

Could restoration be conditional on proving that the current value is the compatibility dispatcher installed by this undici initialization, rather than restoring whenever the value merely changed?

I’d also add a regression where the legacy slot changes during the lazy import and assert that the newer value survives.

This is separate from #1157’s original bug: preserving the dispatcher present before undici initialization is correct; the question is ownership of a later concurrent change.

AI-assisted source review; I have not reproduced this with a real concurrent "setGlobalDispatcher()" + delayed module loader yet, so I’d treat it as a lifecycle/concurrency contract question rather than a confirmed production failure.

Signed-off-by: dvd233 <111864431+dvd233@users.noreply.github.com>
@dvd233

dvd233 commented Oct 15, 2026

Copy link
Copy Markdown
Contributor Author

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.

[Bug] Importing undici@8 in MemoryCore overrides Node's EnvHttpProxyAgent and bypasses HTTP(S)_PROXY

3 participants