fix(network): apply connection timeout in server and extension hosts
Complete the runtime entrypoints from #3404 without changing address-family selection.
This commit is contained in:
@@ -190,6 +190,14 @@ Reachable filesystem routes: `api:fs:read` (attachments), `api:fs:search`
|
|||||||
Maintenance: reviews, changelog entries, and parity claims consult this map;
|
Maintenance: reviews, changelog entries, and parity claims consult this map;
|
||||||
whoever mounts or unmounts a surface updates it in the same change.
|
whoever mounts or unmounts a surface updates it in the same change.
|
||||||
|
|
||||||
|
## Network connections
|
||||||
|
|
||||||
|
Extension activation applies `networkDefaults.ts` before registering handlers.
|
||||||
|
It gives Node connection attempts 5 seconds, matching the web runtime, so quota
|
||||||
|
requests to distant providers can connect. This is an extension-host process
|
||||||
|
default, including other Node connections in that host. Address-family selection
|
||||||
|
stays unchanged; runtimes without the setter retain their existing behavior.
|
||||||
|
|
||||||
## Global OpenCode paths
|
## Global OpenCode paths
|
||||||
|
|
||||||
`opencodeConfigPaths.ts` owns the global config directory for config CRUD,
|
`opencodeConfigPaths.ts` owns the global config directory for config CRUD,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { startGlobalEventWatcher, stopGlobalEventWatcher, setChatViewProvider }
|
|||||||
import { pathsEqualWithNormalizedDriveLetter } from './pathUtils';
|
import { pathsEqualWithNormalizedDriveLetter } from './pathUtils';
|
||||||
import { resolveWorkspaceFolders } from './workspaceResolver';
|
import { resolveWorkspaceFolders } from './workspaceResolver';
|
||||||
import { InlineCommentThreads, SIDEBAR_SURFACE_ID } from './InlineCommentThreads';
|
import { InlineCommentThreads, SIDEBAR_SURFACE_ID } from './InlineCommentThreads';
|
||||||
|
import { applyConnectAttemptTimeout } from './networkDefaults';
|
||||||
|
|
||||||
let chatViewProvider: ChatViewProvider | undefined;
|
let chatViewProvider: ChatViewProvider | undefined;
|
||||||
|
|
||||||
@@ -52,6 +53,7 @@ const formatDurationMs = (value: number | null | undefined) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export async function activate(context: vscode.ExtensionContext) {
|
export async function activate(context: vscode.ExtensionContext) {
|
||||||
|
applyConnectAttemptTimeout();
|
||||||
outputChannel = vscode.window.createOutputChannel('OpenChamber');
|
outputChannel = vscode.window.createOutputChannel('OpenChamber');
|
||||||
|
|
||||||
let moveToRightSidebarScheduled = false;
|
let moveToRightSidebarScheduled = false;
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { test } from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import * as net from 'node:net';
|
||||||
|
import { applyConnectAttemptTimeout } from './networkDefaults';
|
||||||
|
|
||||||
|
test('allows slow connections without changing address-family selection', () => {
|
||||||
|
const previousTimeout = net.getDefaultAutoSelectFamilyAttemptTimeout();
|
||||||
|
const previousFamily = net.getDefaultAutoSelectFamily();
|
||||||
|
try {
|
||||||
|
net.setDefaultAutoSelectFamilyAttemptTimeout(250);
|
||||||
|
assert.equal(applyConnectAttemptTimeout(), true);
|
||||||
|
assert.equal(net.getDefaultAutoSelectFamilyAttemptTimeout(), 5_000);
|
||||||
|
assert.equal(net.getDefaultAutoSelectFamily(), previousFamily);
|
||||||
|
} finally {
|
||||||
|
net.setDefaultAutoSelectFamilyAttemptTimeout(previousTimeout);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('unsupported runtimes retain their existing behavior', () => {
|
||||||
|
assert.equal(applyConnectAttemptTimeout({}), false);
|
||||||
|
assert.equal(applyConnectAttemptTimeout({
|
||||||
|
setDefaultAutoSelectFamilyAttemptTimeout() { throw new Error('unsupported'); },
|
||||||
|
}), false);
|
||||||
|
});
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import * as net from 'node:net';
|
||||||
|
|
||||||
|
// Mirrors the web runtime policy for distant quota endpoints. The extension
|
||||||
|
// host has its own Node fetch stack and does not inherit server defaults.
|
||||||
|
export function applyConnectAttemptTimeout(
|
||||||
|
netModule: Partial<Pick<typeof net, 'setDefaultAutoSelectFamilyAttemptTimeout'>> = net,
|
||||||
|
): boolean {
|
||||||
|
try {
|
||||||
|
if (!netModule.setDefaultAutoSelectFamilyAttemptTimeout) return false;
|
||||||
|
netModule.setDefaultAutoSelectFamilyAttemptTimeout(5_000);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -118,6 +118,10 @@ import { createScheduledTaskService } from './lib/scheduled-tasks/service.js';
|
|||||||
import { createOpenChamberControlService } from './lib/openchamber-control/service.js';
|
import { createOpenChamberControlService } from './lib/openchamber-control/service.js';
|
||||||
import { OpenChamberControlError } from './lib/openchamber-control/error.js';
|
import { OpenChamberControlError } from './lib/openchamber-control/error.js';
|
||||||
import webPush from 'web-push';
|
import webPush from 'web-push';
|
||||||
|
import { applyConnectAttemptTimeout } from './lib/network-defaults.js';
|
||||||
|
|
||||||
|
// Background CLI launches enter here in a fresh process, without CLI defaults.
|
||||||
|
applyConnectAttemptTimeout();
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
|
|||||||
@@ -1,9 +1,25 @@
|
|||||||
import { describe, expect, it, vi } from 'vitest';
|
import { describe, expect, it, vi } from 'vitest';
|
||||||
import net from 'node:net';
|
import net from 'node:net';
|
||||||
|
import { spawnSync } from 'node:child_process';
|
||||||
|
|
||||||
import { applyConnectAttemptTimeout, CONNECT_ATTEMPT_TIMEOUT_MS } from './network-defaults.js';
|
import { applyConnectAttemptTimeout, CONNECT_ATTEMPT_TIMEOUT_MS } from './network-defaults.js';
|
||||||
|
|
||||||
describe('applyConnectAttemptTimeout', () => {
|
describe('applyConnectAttemptTimeout', () => {
|
||||||
|
it('initializes the server entrypoint in a fresh Node process', () => {
|
||||||
|
const serverUrl = new URL('../index.js', import.meta.url).href;
|
||||||
|
const result = spawnSync('node', ['--input-type=module', '--eval', `
|
||||||
|
import net from 'node:net';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
const family = net.getDefaultAutoSelectFamily();
|
||||||
|
net.setDefaultAutoSelectFamilyAttemptTimeout(250);
|
||||||
|
await import(${JSON.stringify(serverUrl)});
|
||||||
|
assert.equal(net.getDefaultAutoSelectFamilyAttemptTimeout(), 5000);
|
||||||
|
assert.equal(net.getDefaultAutoSelectFamily(), family);
|
||||||
|
process.exit(0);
|
||||||
|
`], { encoding: 'utf8', timeout: 15_000, windowsHide: true });
|
||||||
|
expect(result.status, result.stderr).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
it('raises the per-attempt connect timeout on runtimes that expose the setter', () => {
|
it('raises the per-attempt connect timeout on runtimes that expose the setter', () => {
|
||||||
const previous = net.getDefaultAutoSelectFamilyAttemptTimeout();
|
const previous = net.getDefaultAutoSelectFamilyAttemptTimeout();
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -3,6 +3,11 @@
|
|||||||
## Purpose
|
## Purpose
|
||||||
This module fetches quota and usage signals for supported providers in the web server runtime.
|
This module fetches quota and usage signals for supported providers in the web server runtime.
|
||||||
|
|
||||||
|
Node server entrypoints apply `../network-defaults.js` before serving requests,
|
||||||
|
including the daemon launched directly through `server/index.js`. Connection
|
||||||
|
attempts get 5 seconds without changing address-family selection. The VS Code
|
||||||
|
extension applies the same policy in its own process at activation.
|
||||||
|
|
||||||
## Entrypoints and structure
|
## Entrypoints and structure
|
||||||
- `packages/web/server/lib/quota/index.js`: public entrypoint imported by `packages/web/server/index.js`.
|
- `packages/web/server/lib/quota/index.js`: public entrypoint imported by `packages/web/server/index.js`.
|
||||||
- `packages/web/server/lib/quota/routes.js`: Express route registration for quota endpoints.
|
- `packages/web/server/lib/quota/routes.js`: Express route registration for quota endpoints.
|
||||||
|
|||||||
Reference in New Issue
Block a user