From d9b2cdc5937bf5d124b52f4cb5ea479801fbff95 Mon Sep 17 00:00:00 2001 From: yetone Date: Wed, 7 Oct 2026 04:37:28 +0800 Subject: [PATCH] plugin tests: TestHostJSCancellation's ready-wait cancels 1,000 bootstrap waits rather than 30,000, so it finishes inside its 10 s under a full suite's load ready-wait failed twice on 10-07 in full `go test -tags nogui ./...` runs on main ("signal: killed" at 10.00s) and passed alone. The cause is the test's size, not the host's cancellation. The case runs 30,000 fetch+abort rounds, each waiting at least one setImmediate turn. That takes ~4s alone, 4.4-8.5s beside a full go test ./... plus CPU and fresh-script load loops, and more than 10s when starved (taskpolicy -c background with every core busy: killed 3 of 3). The cost per round stays flat from 5,000 to 120,000 rounds (no growth, so no leak), and the counts at the end are exact: retainedWaiters 0, one reaction on the shared ready promise, one drain listener. Those counts are what catches a leak, and they catch it at any size. With 1,000 rounds, leaving the waiter in readyWaiters fails with retainedWaiters 1000, and a reaction per request on the shared ready promise fails with retainedReadyReactions 1000. Before: starved, 3 of 3 runs killed at 10.04-10.26s; -race -count=20 79.9s. After: starved, 5 of 5 pass (ready-wait 0.6-5.6s, mostly node startup); -race -count=20 9.9s. No production code changed. --- internal/plugin/host_flow_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/plugin/host_flow_test.go b/internal/plugin/host_flow_test.go index adefd194..b1b71ad8 100644 --- a/internal/plugin/host_flow_test.go +++ b/internal/plugin/host_flow_test.go @@ -146,7 +146,7 @@ async function main() { unresolved.then = (...args) => { readyReactions++; return originalThen(...args) } initialize(unresolved) run('send({id: 99, result: null})') - for (let iteration = 0; iteration < 30000; iteration++) { + for (let iteration = 0; iteration < 1000; iteration++) { fetchOne() abortOne() await until(idle, 'cancelled bootstrap wait cleans registries') @@ -156,7 +156,7 @@ async function main() { assert.equal(stdout.listenerCount('drain'), 1, 'only shared drain listener remains') const retainedWaiters = run('typeof readyWaiters === "undefined" ? -1 : readyWaiters.size') const retainedReadyReactions = readyReactions - (run('typeof setReady') === 'function' ? 1 : 0) - console.log(JSON.stringify({ cancellations: 30000, idle: idle(), queued: queued(), readyReactions, retainedReadyReactions, retainedWaiters })) + console.log(JSON.stringify({ cancellations: 1000, idle: idle(), queued: queued(), readyReactions, retainedReadyReactions, retainedWaiters })) assert.equal(retainedWaiters, 0, 'cancelled bootstrap leaves no retained waiters') assert.equal(retainedReadyReactions, 0, 'cancelled requests leave no reactions on shared ready') assert.equal(readyReactions, 1, 'only shared initialization reaction remains')