90 lines
2.3 KiB
Python
90 lines
2.3 KiB
Python
from collections.abc import Awaitable, Callable
|
|
|
|
import tractor
|
|
import trio
|
|
|
|
|
|
async def breakpoint_forever() -> None:
|
|
'''
|
|
Indefinitely re-enter debugger in child actor.
|
|
|
|
'''
|
|
while True:
|
|
await trio.sleep(0.1)
|
|
await tractor.pause()
|
|
|
|
|
|
async def name_error() -> None:
|
|
'''
|
|
Raise a ``NameError``.
|
|
|
|
'''
|
|
getattr(doggypants) # noqa
|
|
|
|
|
|
async def spawn_error() -> None:
|
|
'''
|
|
A nested nursery that triggers another ``NameError``.
|
|
|
|
'''
|
|
async with tractor.open_nursery() as an:
|
|
return await tractor.to_actor.run(
|
|
name_error,
|
|
an=an,
|
|
name='name_error_1',
|
|
)
|
|
|
|
|
|
async def main() -> None:
|
|
'''
|
|
The main ``tractor`` routine.
|
|
|
|
The process tree should look as approximately as follows:
|
|
|
|
-python examples/debugging/multi_subactors.py
|
|
|-python -m tractor._child --uid ('name_error', 'a7caf490 ...)
|
|
|-python -m tractor._child --uid ('bp_forever', '1f787a7e ...)
|
|
`-python -m tractor._child --uid ('spawn_error', '52ee14a5 ...)
|
|
`-python -m tractor._child --uid ('name_error', '3391222c ...)
|
|
|
|
'''
|
|
errors: list[BaseException] = []
|
|
|
|
async with tractor.open_nursery(
|
|
debug_mode=True,
|
|
# loglevel='runtime',
|
|
) as an:
|
|
|
|
async def run_and_collect(
|
|
fn: Callable[[], Awaitable[object]],
|
|
) -> None:
|
|
'''
|
|
One-shot whose (boxed) error is stashed instead of
|
|
raised so a sibling's crash never cancels the others
|
|
before they've had their own debugger sessions (the
|
|
'collect all errors' the legacy `run_in_actor()` API
|
|
did implicitly at nursery teardown).
|
|
|
|
'''
|
|
try:
|
|
await tractor.to_actor.run(fn, an=an)
|
|
except tractor.RemoteActorError as rae:
|
|
errors.append(rae)
|
|
|
|
# Spawn all one-shot task actors, collecting (vs.
|
|
# raising) their errors.
|
|
async with trio.open_nursery() as tn:
|
|
tn.start_soon(run_and_collect, breakpoint_forever)
|
|
tn.start_soon(run_and_collect, name_error)
|
|
tn.start_soon(run_and_collect, spawn_error)
|
|
|
|
if errors:
|
|
raise BaseExceptionGroup(
|
|
'multi_subactors errored!',
|
|
errors,
|
|
)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
trio.run(main)
|