fix(quota): raise Node's 250ms connect-attempt cap for provider fetches (#3404)
Node's happy-eyeballs default (autoSelectFamilyAttemptTimeout=250ms) aborts every connect attempt to provider endpoints whose TCP handshake exceeds 250ms, so quota fetches from Node processes fail with "fetch failed" while the Bun-based opencode CLI path succeeds (#3399). Raise the per-attempt cap to 5s via a shared applyConnectAttemptTimeout() helper called from the two Node entrypoints that host the quota module: the Electron main process and the openchamber CLI. Family autoselection stays enabled (::1 and IPv6→IPv4 fallback preserved); runtimes without the setter are a no-op.
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
import net from 'node:net';
|
||||
|
||||
// Node caps each happy-eyeballs connect attempt at 250ms by default
|
||||
// (autoSelectFamilyAttemptTimeout). TCP handshakes to provider endpoints that are
|
||||
// geographically distant routinely take 300-1500ms, so fetch() from a Node process
|
||||
// aborts every attempt (ETIMEDOUT) and surfaces "fetch failed" even though the host
|
||||
// is reachable — e.g. the z.ai quota endpoint from an IPv4-only egress (#3399).
|
||||
//
|
||||
// Every Node process entrypoint that performs provider fetches raises the
|
||||
// per-attempt cap. Family autoselection itself stays enabled, so the IPv6→IPv4
|
||||
// fallback and ::1/localhost servers keep working; disabling it instead breaks
|
||||
// local MCP servers. Runtimes without the setter (Bun's fetch path, older Node)
|
||||
// are a no-op.
|
||||
export const CONNECT_ATTEMPT_TIMEOUT_MS = 5_000;
|
||||
|
||||
export const applyConnectAttemptTimeout = (netModule = net) => {
|
||||
try {
|
||||
netModule.setDefaultAutoSelectFamilyAttemptTimeout(CONNECT_ATTEMPT_TIMEOUT_MS);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user