Orihon.UseCases.Tests intermittently hangs the test host under CPU contention (pre-existing) #67
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found while chasing a CI failure on PR #65. Filing separately because it is pre-existing on main and unrelated to that PR's content.
Symptom
A full
dotnet test tests/Orihon.UseCases.Tests -c Releaserun occasionally never finishes — the test host hangs indefinitely (killed at a 70 s outer timeout). It is a hang, not a slow run: healthy runs take ~2 s.In a captured hang, 229 of 240 tests had completed and the 11 missing ones were the entire
RunEngineTestsclass. Every other class, including all the engine-heavyAnnotationRunTests, had passed. So one test in that class stops progressing and blocks the rest of its (sequential) class while the assembly waits for it.Reproduction and rates
Each figure is from a loop of full-assembly Release runs with
--no-buildand a 70 s per-run timeout:origin/main(4a5e776), idle machineorigin/main, with 6 background CPU hogs (yes > /dev/null)Reading: the trigger is CPU/thread-pool contention, not any particular change. Main reproduces it once given artificial load; the PR branch reproduces it without extra load simply because its added tests raise concurrency. Reverting the PR's
RunEnginechange does not help, and removing its tests does — both consistent with load being the variable.Where it most likely sits
RunEngine.WhenIdleAsync()(Task.WhenAll(inFlight.Values)) is the only unbounded await the engine tests use; every other wait in those tests is a 10 sUntilAsyncdeadline that would fail rather than hang. SeveralRunEngineTestscases await it after driving a stage to a terminal state. A task that never completes — or a snapshot taken as tasks are being re-scheduled — would hang there forever with no diagnostic.Notes for whoever picks this up
dotnet test --blame-hangmasks the bug: 25 runs with blame instrumentation and 10 more under forced CPU load never reproduced it, so the hang dump route needs something else (attachdotnet-stack/dotnet-dumpto the live hung host instead).RunEngineTestsalone never reproduced it (30 runs) — it needs the whole assembly's cross-class parallelism.WhenIdleAsyncan optional timeout for test use (or aWaitAsync(TimeSpan)at the call sites) so the failure mode becomes a readable assertion instead of a hang, then re-run the loop to see which test surfaces.Impact
CI is red at random with no message beyond a timeout, and a hung run costs the whole job's wall clock. Not a production-path defect as far as this investigation went — the engine itself was exercised heavily throughout without misbehaving.
🤖 Generated with Claude Code