diff --git a/src/core/dev/supervisor.test.ts b/src/core/dev/supervisor.test.ts index 4c8bb38e2..a41797f61 100644 --- a/src/core/dev/supervisor.test.ts +++ b/src/core/dev/supervisor.test.ts @@ -292,11 +292,13 @@ describe("DevSupervisor", () => { "produced no output and did not accept connections on port 1 within 0.1s", ); - const server = createServer(); + const server = createServer((socket) => socket.destroy()); await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); const port = (server.address() as { port: number }).port; await waitForPort(port, signal, undefined, 10, 1000); // resolves against a live listener - server.close(); + await new Promise((resolve, reject) => { + server.close((error) => (error ? reject(error) : resolve())); + }); }); test("recent activity keeps a silent port from timing out", async () => { diff --git a/src/io/port.ts b/src/io/port.ts index 79c90fe44..b2423f5db 100644 --- a/src/io/port.ts +++ b/src/io/port.ts @@ -44,12 +44,25 @@ export function waitForPort( const startedAt = Date.now(); const since = lastActivityAt ?? (() => startedAt); return new Promise((resolve, reject) => { + let socket: ReturnType | undefined; + let retry: ReturnType | undefined; + + const cleanup = () => { + socket?.destroy(); + if (retry) clearTimeout(retry); + signal.removeEventListener("abort", onAbort); + }; + const onAbort = () => { + cleanup(); + reject(new Error("Aborted while waiting for the agent to become ready.")); + }; const attempt = () => { if (signal.aborted) { - reject(new Error("Aborted while waiting for the agent to become ready.")); + onAbort(); return; } if (Date.now() - since() > idleMs) { + cleanup(); reject( new Error( `Agent produced no output and did not accept connections on port ${port} within ${idleMs / 1000}s.`, @@ -57,15 +70,22 @@ export function waitForPort( ); return; } - const socket = connect({ port, host: "127.0.0.1" }, () => { - socket.destroy(); + socket = connect({ port, host: "127.0.0.1" }, () => { + cleanup(); resolve(); }); socket.on("error", () => { - socket.destroy(); - setTimeout(attempt, intervalMs); + socket?.destroy(); + socket = undefined; + if (signal.aborted) { + onAbort(); + return; + } + retry = setTimeout(attempt, intervalMs); }); }; + + signal.addEventListener("abort", onAbort, { once: true }); attempt(); }); }