| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
The TestChildProcessCleanup tests asserted that spawned writers had started after fixed sleeps (0.5s startup, 0.3s observation window). On loaded CI runners the child interpreter can take longer than that to boot, so the "child should be writing" assertion failed with "assert 0 > 0" before the cleanup logic under test ever ran. Replace the fixed sleeps with bounded polling: - _wait_for_first_write polls until a marker file has grown, proving the writer reached its write loop, with a 15s timeout. - _wait_for_writes_to_stop polls until two samples taken 0.3s apart (3x the writers' 0.1s write interval) observe the same size; if the file never stops growing the timeout fails the test, so a genuine cleanup failure is still reported. Also terminate the spawned process tree in each test's finally block, so a failed assertion can no longer leak a running process tree, and collect garbage before leaving each test so subprocess transports are finalized while the test's ResourceWarning filters are still active. Removing the unconditional sleeps also makes the tests faster.
… tests Two follow-up fixes to the child process cleanup tests: Require three consecutive stable samples before declaring writes stopped. The previous check exited on the first pair of samples 0.3s apart with no growth, retrying within the 15s budget, which made it easier for a CPU-starved (but alive) writer to be mistaken for a terminated one. The counter resets on any observed growth, and a file that never stops growing still fails the test via the timeout. Only re-terminate the process tree in the finally block if the test failed before reaching its own _terminate_process_tree call. The unconditional second call ran termination against an already-closed job object handle on Windows and logged a spurious fallback warning on POSIX in every passing run. The skipped branch only executes on failing runs, so it is excluded from coverage.
The cleanup tests killed the spawned process tree but never awaited the process or closed its pipe streams. The asyncio subprocess transports stayed referenced by the per-test event loop, became garbage once that loop closed, and were finalized during a later test on the same worker. Under filterwarnings=error the resulting ResourceWarning fails whichever test happens to be running; on Windows the warning itself can die inside the transport repr with 'I/O operation on closed pipe'. A gc.collect() inside the test cannot help because the transports are still referenced by the live event loop at that point. After the stop-of-writes check confirms the tree is dead, each test now waits on the process (bounded, tolerant of the already-exited process), closes stdin, drains stdout to EOF so the event loop observes the pipe closure and can close the subprocess transport, then closes stdout. The same disposal runs in the failure-path cleanup after its kill. Draining works for both process flavors used on the platforms (anyio Process and the Windows FallbackProcess, which has no aclose), and EOF is guaranteed because every process that inherited the pipe handle is already dead.
| Back | FazBrowse Home | New Git URL |
Deflakes tests/client/test_stdio.py::TestChildProcessCleanup, the most frequent flake on v1.x CI (Windows legs). Tests-only; nothing under src/ is touched.
Motivation and Context
These three tests have two independent failure modes, both confirmed from CI failure logs and reproduced under load on 2-core Windows runners:
Measured on 2-core Windows runners with three CPU-load processes (100 repetitions per arm per Python version, deliberately harsher than real CI):
What changed
The first two commits also reached the maxisbey/v1x-interaction-backport branch via #2837; the hunks are identical, so merging both into v1.x converges cleanly, with the third commit new here.
How Has This Been Tested?
Full v1.x gate (pytest + 100% line and branch coverage) green. Locally: 70+ repetitions of the class including runs under full-core CPU load, cross-test GC probes (-n 0 with a follow-on test file) clean, and zero warning output in any run. The load-rig confirmation run for the final arm completed: 0 failures in 100 repetitions on each of Python 3.10 and 3.13.
Breaking Changes
None. Tests-only.
Types of changes
Checklist
AI Disclaimer