66from collections .abc import Callable , Awaitable
77from contextlib import AsyncExitStack
88from inspect import isawaitable , signature , _empty
9+ from time import time
910from typing import TypeVar , Any , Iterable , cast
1011
1112import anyio
@@ -56,18 +57,22 @@ def __init__(
5657 prepare_timeout : float = 1 ,
5758 start_timeout : float = 1 ,
5859 stop_timeout : float = 1 ,
60+ global_start_timeout : float | None = None ,
5961 ):
6062 """
6163 Args:
6264 name: The name to give to the module.
6365 prepare_timeout: The time to wait (in seconds) for the "prepare" phase to complete.
6466 start_timeout: The time to wait (in seconds) for the "start" phase to complete.
6567 stop_timeout: The time to wait (in seconds) for the "stop" phase to complete.
68+ global_start_timeout: The time to wait (in seconds) for the "prepare" and "start"
69+ phases to complete.
6670 """
6771 self ._initialized = False
6872 self ._prepare_timeout = prepare_timeout
6973 self ._start_timeout = start_timeout
7074 self ._stop_timeout = stop_timeout
75+ self ._global_start_timeout = global_start_timeout
7176 self ._parent : Module | None = None
7277 self ._context = Context ()
7378 self ._prepared = Event ()
@@ -327,7 +332,12 @@ async def __aenter__(self) -> Module:
327332 self ._task_group = await exit_stack .enter_async_context (create_task_group ())
328333 self ._exceptions = []
329334 self ._phase = "preparing"
330- with move_on_after (self ._prepare_timeout ) as scope :
335+ if self ._global_start_timeout is None :
336+ prepare_timeout = self ._prepare_timeout
337+ else :
338+ prepare_timeout = self ._global_start_timeout
339+ t0 = time ()
340+ with move_on_after (prepare_timeout ) as scope :
331341 self ._task_group .start_soon (self ._prepare , name = f"{ self .path } _prepare" )
332342 await self ._all_prepared ()
333343 if scope .cancelled_caught :
@@ -336,7 +346,12 @@ async def __aenter__(self) -> Module:
336346 self ._exit .set ()
337347 else :
338348 self ._phase = "starting"
339- with move_on_after (self ._start_timeout ) as scope :
349+ if self ._global_start_timeout is None :
350+ start_timeout = self ._start_timeout
351+ else :
352+ elapsed_time = time () - t0
353+ start_timeout = max (self ._global_start_timeout - elapsed_time , 0 )
354+ with move_on_after (start_timeout ) as scope :
340355 self ._task_group .start_soon (self ._start , name = f"{ self .path } start" )
341356 await self ._all_started ()
342357 if scope .cancelled_caught :
0 commit comments