@@ -350,6 +350,7 @@ async def test_nested_process_tree(self):
350350 with tempfile .NamedTemporaryFile (mode = "w" , delete = False ) as f3 :
351351 grandchild_file = f3 .name
352352
353+ proc = None
353354 try :
354355 # Simple nested process tree test
355356 # We create parent -> child -> grandchild, each writing to a file
@@ -405,9 +406,16 @@ async def test_nested_process_tree(self):
405406 for file_path , name in [(parent_file , "parent" ), (child_file , "child" ), (grandchild_file , "grandchild" )]:
406407 if os .path .exists (file_path ): # pragma: no branch
407408 initial_size = os .path .getsize (file_path )
408- await anyio .sleep (0.3 )
409- new_size = os .path .getsize (file_path )
410- assert new_size > initial_size , f"{ name } process should be writing"
409+ # Under high load (e.g. CI + xdist), short fixed sleeps can be flaky on Windows.
410+ # Poll for growth within a small deadline rather than asserting after a single sleep.
411+ deadline = time .monotonic () + 3.0
412+ while time .monotonic () < deadline :
413+ await anyio .sleep (0.1 )
414+ new_size = os .path .getsize (file_path )
415+ if new_size > initial_size : # pragma: no branch
416+ break
417+ else : # pragma: no cover
418+ raise AssertionError (f"{ name } process should be writing" )
411419
412420 # Terminate the whole tree
413421 await _terminate_process_tree (proc )
@@ -424,6 +432,14 @@ async def test_nested_process_tree(self):
424432 print ("SUCCESS: All processes in tree terminated" )
425433
426434 finally :
435+ # If the "is writing" assertions fail, ensure we still terminate the process tree to
436+ # avoid leaking subprocesses (which can cause cascading failures on Windows).
437+ if proc is not None : # pragma: no branch
438+ try :
439+ await _terminate_process_tree (proc )
440+ except (OSError , RuntimeError , ProcessLookupError ): # pragma: no cover
441+ pass
442+
427443 # Clean up all marker files
428444 for f in [parent_file , child_file , grandchild_file ]:
429445 try :
0 commit comments