Skip to content

Commit b5b91c9

Browse files
fix(vitest-pool-workers): dispose remote proxy sessions on pool close (#12682)
Co-authored-by: Dario Piotrowicz <dario.piotrowicz@gmail.com>
1 parent 5f7aaf2 commit b5b91c9

File tree

5 files changed

+84
-2
lines changed

5 files changed

+84
-2
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@cloudflare/vitest-pool-workers": patch
3+
---
4+
5+
Fix resource leak where remote proxy sessions were not disposed during pool shutdown, causing vitest processes to hang.

packages/vitest-pool-workers/src/pool/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ function filterTails(
199199
}
200200

201201
/** Map that maps worker configPaths to their existing remote proxy session data (if any) */
202-
const remoteProxySessionsDataMap = new Map<
202+
export const remoteProxySessionsDataMap = new Map<
203203
string,
204204
{
205205
session: RemoteProxySession;

packages/vitest-pool-workers/src/pool/index.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ import { experimental_readRawConfig } from "wrangler";
2929
import { workerdBuiltinModules } from "../shared/builtin-modules";
3030
import { createChunkingSocket } from "../shared/chunking-socket";
3131
import { CompatibilityFlagAssertions } from "./compatibility-flag-assertions";
32-
import { OPTIONS_PATH, parseProjectOptions } from "./config";
32+
import {
33+
OPTIONS_PATH,
34+
parseProjectOptions,
35+
remoteProxySessionsDataMap,
36+
} from "./config";
3337
import { guessWorkerExports } from "./guess-exports";
3438
import {
3539
getProjectPath,
@@ -1284,6 +1288,14 @@ export default function (ctx: Vitest): ProcessPool {
12841288
}
12851289
}
12861290
allProjects.clear();
1291+
// Dispose remote proxy sessions to prevent handle leaks
1292+
log.debug("Disposing remote proxy sessions...");
1293+
for (const sessionData of remoteProxySessionsDataMap.values()) {
1294+
if (sessionData?.session?.dispose) {
1295+
promises.push(sessionData.session.dispose());
1296+
}
1297+
}
1298+
remoteProxySessionsDataMap.clear();
12871299
await Promise.all(promises);
12881300
},
12891301
};
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import dedent from "ts-dedent";
2+
import { test } from "./helpers";
3+
4+
// This test requires CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN
5+
// environment variables to be set, as it exercises remote proxy sessions
6+
// that connect to the Cloudflare API.
7+
test.skipIf(
8+
!process.env.CLOUDFLARE_ACCOUNT_ID || !process.env.CLOUDFLARE_API_TOKEN
9+
)(
10+
"disposes remote proxy sessions on pool close",
11+
async ({ expect, seed, vitestRun }) => {
12+
await seed({
13+
"vitest.config.mts": dedent`
14+
import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config";
15+
export default defineWorkersConfig({
16+
test: {
17+
reporters: ["hanging-process", "verbose"],
18+
poolOptions: {
19+
workers: {
20+
wrangler: { configPath: "./wrangler.jsonc" },
21+
},
22+
},
23+
}
24+
});
25+
`,
26+
"wrangler.jsonc": dedent`
27+
{
28+
"name": "test-worker",
29+
"main": "src/index.ts",
30+
"compatibility_date": "2025-06-01",
31+
"compatibility_flags": ["nodejs_compat"],
32+
"ai": { "binding": "AI" },
33+
"account_id": "${process.env.CLOUDFLARE_ACCOUNT_ID}"
34+
}
35+
`,
36+
"src/index.ts": dedent`
37+
export default {
38+
async fetch(request, env, ctx) {
39+
return new Response("Hello");
40+
}
41+
}
42+
`,
43+
"src/index.test.ts": dedent`
44+
import { SELF } from "cloudflare:test";
45+
import { it, expect } from "vitest";
46+
it("responds with Hello", async () => {
47+
const response = await SELF.fetch("http://localhost/");
48+
expect(await response.text()).toBe("Hello");
49+
});
50+
`,
51+
});
52+
53+
const result = await vitestRun({
54+
flags: ["--reporter=hanging-process", "--reporter=verbose"],
55+
});
56+
57+
expect(result.stderr).not.toContain(
58+
"something prevents Vite server from exiting"
59+
);
60+
},
61+
20_000
62+
);

packages/vitest-pool-workers/turbo.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
"tasks": {
55
"build": {
66
"outputs": ["dist/**"]
7+
},
8+
"test": {
9+
"env": ["CLOUDFLARE_ACCOUNT_ID", "CLOUDFLARE_API_TOKEN"]
710
}
811
}
912
}

0 commit comments

Comments
 (0)