Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions test/js/web/workers/worker-terminate-lifetime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,10 @@ test(
// response stream's producer by writing through the stream's wrapper into a source that sweep had
// already freed (heap-use-after-free WRITE under ASAN). The tasklet now holds a counted ref on the
// source for as long as it is its producer.
//
// The worker exits once every response has been touched, not on a clock: a burst of 48 loopback
// connections takes 100ms+ to establish on the macOS x64 CI hosts, so a fixed deadline exited
// before the state it is meant to tear down existed.
test(
"worker exit with streaming-request-body fetches whose response.body was touched",
async () => {
Expand All @@ -977,23 +981,32 @@ test(
const { Worker } = require("node:worker_threads");
const server = Bun.serve({ port: 0, fetch(req) { return new Response(req.body); } });
const N = 6;
const J = 8;
let done = 0;
for (let i = 0; i < N; i++) {
const w = new Worker(\`
const keep = [];
let touched = 0;
for (let j = 0; j < 8; j++) {
for (let j = 0; j < \${J}; j++) {
let ctrl;
const body = new ReadableStream({ start(c) { ctrl = c; c.enqueue(new Uint8Array(1024)); } });
const p = fetch("\${server.url}", { method: "POST", body, duplex: "half" })
.then((r) => { keep.push(r.body); const rd = r.body.getReader(); rd.read(); keep.push(rd); touched++; })
.catch(() => {});
.then((r) => {
keep.push(r.body); const rd = r.body.getReader(); rd.read(); keep.push(rd);
// Exit with that state alive: every response touched while its request body is
// still streaming.
if (++touched === \${J}) setTimeout(() => process.exit(0), 0);
Comment thread
robobun marked this conversation as resolved.
Resolved
})
.catch((e) => { console.error("fetch failed:", e); process.exit(3); });
keep.push(p, ctrl);
setInterval(() => { try { ctrl.enqueue(new Uint8Array(512)); } catch {} }, 5);
}
// Exit with that state alive; exit code 3 if no fetch ever reached it (the test would
// then not be exercising what it claims to).
setTimeout(() => process.exit(touched > 0 ? 0 : 3), 150 + \${(i * 13) % 60});
// Only a failure reaches this: the test would otherwise hang to its timeout without
// saying which worker never got its responses.
setTimeout(() => {
console.error("worker \${i}: " + touched + " of \${J} responses touched");
process.exit(3);
}, ${timeout / 2});
\`, { eval: true });
w.on("error", (e) => { console.error(e); process.exit(1); });
w.on("exit", (code) => {
Expand Down
Loading