2from collections.abc
import Callable
9ITERATION_PERIOD_SECONDS = 0.5
11logger = logging.getLogger(__name__)
21 relax_period_seconds: float = ITERATION_PERIOD_SECONDS,
22 total_wait_seconds: float = TOTAL_WAIT_SECONDS,
25 Waits for some external event for `total_wait_seconds` and
26 calls `func` every `relax_period_seconds`.
27 If `func` raises NotReady exception, the waiting continues.
28 If `func` succesfully returns, wait_until() returns the same value.
29 After `total_wait_seconds` of unsuccesfull checks wait_until()
34 .. code-block:: python
36 async def try_to_connect_db():
37 if not db_conn_is_ok():
40 await wait_until(try_to_connect_db)
42 @throws TimeoutError after `total_wait_seconds` of unsuccesfull checks
43 @note If possible, use @ref testpoint instead. @ref testpoint is
44 an explicit message from the server "I'm ready", while wait_until()
45 uses an implicit idea "A condition is met, so I can continue".
47 @ingroup userver_testsuite
49 start = datetime.datetime.now()
50 while datetime.datetime.now() - start < datetime.timedelta(seconds=total_wait_seconds):
54 await asyncio.sleep(relax_period_seconds)
62 catch: Any | tuple = (),
63 relax_period_seconds: float = ITERATION_PERIOD_SECONDS,
64 total_wait_seconds: float = TOTAL_WAIT_SECONDS,
65 failure_msg: str =
'Timeout happened while waiting for an event',
66 relax_msg: str |
None =
None,
69 Waits for some external event for `total_wait_seconds` and
70 calls `check` every `relax_period_seconds`.
71 If `check` returns False or raises NotReady exception
72 (or any exception type referenced in `catch`), the waiting continues.
73 If `check` returns True, wait_until() stops and returns.
74 After `total_wait_seconds` of unsuccesfull checks wait_until()
79 .. code-block:: python
82 return await conn.is_ready()
84 await wait_until(try_to_connect_db)
86 @throws TimeoutError after `total_wait_seconds` of unsuccesfull checks
87 @note If possible, use @ref testpoint instead. @ref testpoint is
88 an explicit message from the server "I'm ready", while wait_until()
89 uses an implicit idea "A condition is met, so I can continue".
91 @ingroup userver_testsuite
94 if isinstance(catch, tuple):
98 exceptions = (NotReady, *exceptions)
103 if inspect.isawaitable(result):
112 logger.warning(
'%s', relax_msg)
113 raise NotReady
from None
118 relax_period_seconds=relax_period_seconds,
119 total_wait_seconds=total_wait_seconds,
122 assert False, failure_msg