Compare commits
4 Commits
023dbf89e4
...
8724cc3915
| Author | SHA1 | Date |
|---|---|---|
|
|
8724cc3915 | |
|
|
1c0ddc373a | |
|
|
ac3bc11332 | |
|
|
15b8bd27ae |
|
|
@ -36,4 +36,5 @@ from ._beg import (
|
|||
)
|
||||
from ._taskc import (
|
||||
maybe_raise_from_masking_exc as maybe_raise_from_masking_exc,
|
||||
start_or_cancel as start_or_cancel,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ from types import (
|
|||
TracebackType,
|
||||
)
|
||||
from typing import (
|
||||
Any,
|
||||
Awaitable,
|
||||
Callable,
|
||||
Type,
|
||||
TYPE_CHECKING,
|
||||
)
|
||||
|
|
@ -295,3 +298,53 @@ async def maybe_raise_from_masking_exc(
|
|||
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
async def start_or_cancel(
|
||||
nursery: trio.Nursery,
|
||||
async_fn: Callable[..., Awaitable[Any]],
|
||||
*args,
|
||||
name: object = None,
|
||||
|
||||
) -> Any:
|
||||
'''
|
||||
Like `trio.Nursery.start()` but DON'T mask an out-of-band
|
||||
cancellation as a (lossy) startup failure.
|
||||
|
||||
`trio.Nursery.start()` raises a generic
|
||||
`RuntimeError("child exited without calling
|
||||
task_status.started()")` whenever the started task exits
|
||||
BEFORE calling `task_status.started()` — INCLUDING the very
|
||||
common case where the child was cancelled out-of-band by an
|
||||
*ancestor* cancel-scope erroring/cancelling. In that case the
|
||||
original `trio.Cancelled` is swallowed and the caller is left
|
||||
with an opaque, root-cause-detached `RuntimeError`.
|
||||
|
||||
This wrapper re-surfaces any ambient (effective, hence
|
||||
ancestor-inclusive) cancellation via
|
||||
`trio.lowlevel.checkpoint_if_cancelled()` so the real
|
||||
`trio.Cancelled` (carrying trio's auto-generated reason which
|
||||
points at the true root exc) propagates instead. Only when we
|
||||
are NOT under cancellation is the "didn't call `.started()`"
|
||||
`RuntimeError` a genuine startup-protocol bug worth surfacing,
|
||||
so it's re-raised as-is in that case.
|
||||
|
||||
'''
|
||||
try:
|
||||
return await nursery.start(
|
||||
async_fn,
|
||||
*args,
|
||||
name=name,
|
||||
)
|
||||
except RuntimeError as rte:
|
||||
if (
|
||||
rte.args
|
||||
and
|
||||
'started' in rte.args[0]
|
||||
):
|
||||
# re-raises the in-flight `trio.Cancelled` IFF we're
|
||||
# under effective cancellation; else a cheap no-op and
|
||||
# we fall through to re-raise the genuine startup RTE.
|
||||
await trio.lowlevel.checkpoint_if_cancelled()
|
||||
|
||||
raise
|
||||
|
|
|
|||
Loading…
Reference in New Issue