userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
sync.py
1
import
asyncio
2
from
collections.abc
import
Callable
3
import
datetime
4
import
inspect
5
import
logging
6
from
typing
import
Any
7
8
TOTAL_WAIT_SECONDS = 30
9
ITERATION_PERIOD_SECONDS = 0.5
10
11
logger = logging.getLogger(__name__)
12
13
14
class
NotReady
(Exception):
15
pass
16
17
18
async def
wait_until
(
19
func: Callable,
20
*,
21
relax_period_seconds: float = ITERATION_PERIOD_SECONDS,
22
total_wait_seconds: float = TOTAL_WAIT_SECONDS,
23
) -> Any:
24
"""
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` successfully returns, wait_until() returns the same value.
29
After `total_wait_seconds` of unsuccessful checks wait_until()
30
raises TimeoutError.
31
32
Example:
33
34
.. code-block:: python
35
36
async def try_to_connect_db():
37
if not db_conn_is_ok():
38
raise NotReady()
39
40
await wait_until(try_to_connect_db)
41
42
@throws TimeoutError after `total_wait_seconds` of unsuccessful 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".
46
47
@ingroup userver_testsuite
48
"""
49
start = datetime.datetime.now()
50
while
datetime.datetime.now() - start < datetime.timedelta(seconds=total_wait_seconds):
51
try
:
52
return
await func()
53
except
NotReady:
54
await asyncio.sleep(relax_period_seconds)
55
56
raise
TimeoutError()
57
58
59
async def
wait
(
60
check: Callable,
61
*,
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
,
67
) ->
None
:
68
"""
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 unsuccessful checks wait_until()
75
raises TimeoutError.
76
77
Example:
78
79
.. code-block:: python
80
81
async def is_ready():
82
return await conn.is_ready()
83
84
await wait_until(try_to_connect_db)
85
86
@throws TimeoutError after `total_wait_seconds` of unsuccessful 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".
90
91
@ingroup userver_testsuite
92
"""
93
94
if
isinstance(catch, tuple):
95
exceptions = catch
96
else
:
97
exceptions = (catch,)
98
exceptions = (NotReady, *exceptions)
99
100
async def
func():
101
try
:
102
result = check()
103
if
inspect.isawaitable(result):
104
ok = await result
105
else
:
106
ok = result
107
if
ok:
108
return
109
except
exceptions:
110
pass
111
112
logger.warning(
'%s'
, relax_msg)
113
raise
NotReady
from
None
114
115
try
:
116
await
wait_until
(
117
func,
118
relax_period_seconds=relax_period_seconds,
119
total_wait_seconds=total_wait_seconds,
120
)
121
except
TimeoutError:
122
assert
False
, failure_msg
testsuite
pytest_plugins
pytest_userver
utils
sync.py
Generated on
for userver by
Doxygen
1.17.0