@@ -221,6 +221,32 @@ def sigint_handler(signum, frame):
221221 raise
222222
223223
224+ async def _wait_for_file_growth (
225+ file_path : str ,
226+ description : str = "process" ,
227+ timeout : float = 10.0 ,
228+ poll_interval : float = 0.2 ,
229+ ) -> None :
230+ """Wait until a file exists, has content, and is actively growing.
231+
232+ Polls the file size at regular intervals until it observes growth,
233+ raising AssertionError if the timeout is exceeded. This replaces
234+ fixed-duration sleeps that cause flaky tests on slow CI machines.
235+ """
236+ deadline = time .monotonic () + timeout
237+ prev_size = - 1
238+
239+ while time .monotonic () < deadline :
240+ if os .path .exists (file_path ):
241+ size = os .path .getsize (file_path )
242+ if size > 0 and prev_size >= 0 and size > prev_size :
243+ return # File is growing
244+ prev_size = size
245+ await anyio .sleep (poll_interval )
246+
247+ raise AssertionError (f"{ description } did not start writing within { timeout } s" )
248+
249+
224250class TestChildProcessCleanup :
225251 """Tests for child process cleanup functionality using _terminate_process_tree.
226252
@@ -296,19 +322,9 @@ async def test_basic_child_process_cleanup(self):
296322 # Start the parent process
297323 proc = await _create_platform_compatible_process (sys .executable , ["-c" , parent_script ])
298324
299- # Wait for processes to start
300- await anyio .sleep (0.5 )
301-
302- # Verify parent started
303- assert os .path .exists (parent_marker ), "Parent process didn't start"
304-
305- # Verify child is writing
306- if os .path .exists (marker_file ): # pragma: no branch
307- initial_size = os .path .getsize (marker_file )
308- await anyio .sleep (0.3 )
309- size_after_wait = os .path .getsize (marker_file )
310- assert size_after_wait > initial_size , "Child process should be writing"
311- print (f"Child is writing (file grew from { initial_size } to { size_after_wait } bytes)" )
325+ # Wait for parent and child to start (poll instead of fixed sleep)
326+ await _wait_for_file_growth (parent_marker , "parent process" )
327+ await _wait_for_file_growth (marker_file , "child process" )
312328
313329 # Terminate using our function
314330 print ("Terminating process and children..." )
@@ -398,16 +414,10 @@ async def test_nested_process_tree(self):
398414 # Start the parent process
399415 proc = await _create_platform_compatible_process (sys .executable , ["-c" , parent_script ])
400416
401- # Let all processes start
402- await anyio .sleep (1.0 )
403-
404- # Verify all are writing
405- for file_path , name in [(parent_file , "parent" ), (child_file , "child" ), (grandchild_file , "grandchild" )]:
406- if os .path .exists (file_path ): # pragma: no branch
407- 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"
417+ # Wait for all processes to start writing (poll instead of fixed sleep)
418+ await _wait_for_file_growth (parent_file , "parent process" )
419+ await _wait_for_file_growth (child_file , "child process" )
420+ await _wait_for_file_growth (grandchild_file , "grandchild process" )
411421
412422 # Terminate the whole tree
413423 await _terminate_process_tree (proc )
@@ -477,15 +487,8 @@ def handle_term(sig, frame):
477487 # Start the parent process
478488 proc = await _create_platform_compatible_process (sys .executable , ["-c" , parent_script ])
479489
480- # Let child start writing
481- await anyio .sleep (0.5 )
482-
483- # Verify child is writing
484- if os .path .exists (marker_file ): # pragma: no branch
485- size1 = os .path .getsize (marker_file )
486- await anyio .sleep (0.3 )
487- size2 = os .path .getsize (marker_file )
488- assert size2 > size1 , "Child should be writing"
490+ # Wait for child to start writing (poll instead of fixed sleep)
491+ await _wait_for_file_growth (marker_file , "child process" )
489492
490493 # Terminate - this will kill the process group even if parent exits first
491494 await _terminate_process_tree (proc )
0 commit comments