@@ -1007,6 +1007,60 @@ async def operation() -> str:
10071007 asyncio .run (run ())
10081008
10091009
1010+ def test_poll_until_terminal_status_async_does_not_retry_reused_coroutines ():
1011+ async def run () -> None :
1012+ attempts = {"count" : 0 }
1013+ shared_status_coroutine = asyncio .sleep (0 , result = "running" )
1014+
1015+ async def get_status () -> str :
1016+ attempts ["count" ] += 1
1017+ return await shared_status_coroutine
1018+
1019+ with pytest .raises (
1020+ RuntimeError , match = "cannot reuse already awaited coroutine"
1021+ ):
1022+ await poll_until_terminal_status_async (
1023+ operation_name = "async poll reused coroutine" ,
1024+ get_status = get_status ,
1025+ is_terminal_status = lambda value : value == "completed" ,
1026+ poll_interval_seconds = 0.0001 ,
1027+ max_wait_seconds = 1.0 ,
1028+ max_status_failures = 5 ,
1029+ )
1030+
1031+ assert attempts ["count" ] == 2
1032+
1033+ asyncio .run (run ())
1034+
1035+
1036+ def test_retry_operation_async_does_not_retry_reused_coroutines ():
1037+ async def run () -> None :
1038+ attempts = {"count" : 0 }
1039+
1040+ async def shared_operation () -> str :
1041+ raise ValueError ("transient" )
1042+
1043+ shared_operation_coroutine = shared_operation ()
1044+
1045+ async def operation () -> str :
1046+ attempts ["count" ] += 1
1047+ return await shared_operation_coroutine
1048+
1049+ with pytest .raises (
1050+ RuntimeError , match = "cannot reuse already awaited coroutine"
1051+ ):
1052+ await retry_operation_async (
1053+ operation_name = "async retry reused coroutine" ,
1054+ operation = operation ,
1055+ max_attempts = 5 ,
1056+ retry_delay_seconds = 0.0001 ,
1057+ )
1058+
1059+ assert attempts ["count" ] == 2
1060+
1061+ asyncio .run (run ())
1062+
1063+
10101064def test_async_poll_until_terminal_status_allows_immediate_terminal_on_zero_max_wait ():
10111065 async def run () -> None :
10121066 status = await poll_until_terminal_status_async (
@@ -2056,6 +2110,36 @@ async def get_next_page(page: int) -> dict:
20562110 asyncio .run (run ())
20572111
20582112
2113+ def test_collect_paginated_results_async_does_not_retry_reused_coroutines ():
2114+ async def run () -> None :
2115+ attempts = {"count" : 0 }
2116+ shared_page_coroutine = asyncio .sleep (
2117+ 0 , result = {"current" : 1 , "total" : 2 , "items" : []}
2118+ )
2119+
2120+ async def get_next_page (page : int ) -> dict :
2121+ attempts ["count" ] += 1
2122+ return await shared_page_coroutine
2123+
2124+ with pytest .raises (
2125+ RuntimeError , match = "cannot reuse already awaited coroutine"
2126+ ):
2127+ await collect_paginated_results_async (
2128+ operation_name = "async paginated reused coroutine" ,
2129+ get_next_page = get_next_page ,
2130+ get_current_page_batch = lambda response : response ["current" ],
2131+ get_total_page_batches = lambda response : response ["total" ],
2132+ on_page_success = lambda response : None ,
2133+ max_wait_seconds = 1.0 ,
2134+ max_attempts = 5 ,
2135+ retry_delay_seconds = 0.0001 ,
2136+ )
2137+
2138+ assert attempts ["count" ] == 2
2139+
2140+ asyncio .run (run ())
2141+
2142+
20592143def test_wait_for_job_result_returns_fetched_value ():
20602144 status_values = iter (["running" , "completed" ])
20612145
0 commit comments