forked from goodboy/tractor
End the `pdb` SIGINT handling madness
Turns out this is a lower level issue in terms of the stdlib's default `pdb.Pdb` settings and how they conflict with `trio`s cancellation and KBI handling. The details are hashed out more thoroughly in python-trio/trio#1155. Maybe we can get a fix in trio so things are solved under our feet :)pdb_madness
parent
e27dc2e244
commit
e51c2620e5
|
@ -117,9 +117,13 @@ async def _main(
|
|||
# Note that if the current actor is the arbiter it is desirable
|
||||
# for it to stay up indefinitely until a re-election process has
|
||||
# taken place - which is not implemented yet FYI).
|
||||
return await _start_actor(
|
||||
actor, main, host, port, arbiter_addr=arbiter_addr
|
||||
)
|
||||
|
||||
try:
|
||||
return await _start_actor(
|
||||
actor, main, host, port, arbiter_addr=arbiter_addr
|
||||
)
|
||||
finally:
|
||||
logger.info("Root actor terminated")
|
||||
|
||||
|
||||
def run(
|
||||
|
|
|
@ -767,8 +767,8 @@ class Actor:
|
|||
finally:
|
||||
log.info("Root nursery complete")
|
||||
|
||||
# tear down all lifetime contexts
|
||||
# api idea: ``tractor.open_context()``
|
||||
# tear down all lifetime contexts if not in guest mode
|
||||
# XXX: should this just be in the entrypoint?
|
||||
log.warning("Closing all actor lifetime contexts")
|
||||
self._lifetime_stack.close()
|
||||
|
||||
|
|
|
@ -6,12 +6,10 @@ import sys
|
|||
from functools import partial
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import Awaitable, Tuple, Optional, Callable, AsyncIterator
|
||||
# import signal
|
||||
|
||||
from async_generator import aclosing
|
||||
import tractor
|
||||
import trio
|
||||
from trio.testing import wait_all_tasks_blocked
|
||||
|
||||
from .log import get_logger
|
||||
from . import _state
|
||||
|
@ -132,19 +130,6 @@ async def _acquire_debug_lock(uid: Tuple[str, str]) -> AsyncIterator[None]:
|
|||
log.error(f"TTY lock released by {task_name}:{uid}")
|
||||
|
||||
|
||||
def handler(signum, frame):
|
||||
"""Block SIGINT while in debug to avoid deadlocks with cancellation.
|
||||
"""
|
||||
print(
|
||||
"tractor ignores SIGINT while in debug mode\n"
|
||||
"If you have a special need for it please open an issue.\n"
|
||||
)
|
||||
|
||||
|
||||
# don't allow those stdlib mofos to mess with sigint handler
|
||||
pdbpp.pdb.Pdb.sigint_handler = handler
|
||||
|
||||
|
||||
# @contextmanager
|
||||
# def _disable_sigint():
|
||||
# try:
|
||||
|
@ -269,14 +254,29 @@ def _breakpoint(debug_func) -> Awaitable[None]:
|
|||
log.debug("Entering the synchronous world of pdb")
|
||||
debug_func(actor)
|
||||
|
||||
|
||||
# user code **must** await this!
|
||||
return _bp()
|
||||
|
||||
|
||||
def _mk_pdb():
|
||||
# XXX: setting these flags on the pdb instance are absolutely
|
||||
# critical to having ctrl-c work in the ``trio`` standard way!
|
||||
# The stdlib's pdb supports entering the current sync frame
|
||||
# on a SIGINT, with ``trio`` we pretty much never want this
|
||||
# and we did we can handle it in the ``tractor`` task runtime.
|
||||
|
||||
pdb = PdbwTeardown()
|
||||
pdb.allow_kbdint = True
|
||||
pdb.nosigint = True
|
||||
|
||||
return pdb
|
||||
|
||||
|
||||
def _set_trace(actor):
|
||||
log.critical(f"\nAttaching pdb to actor: {actor.uid}\n")
|
||||
PdbwTeardown().set_trace(
|
||||
|
||||
pdb = _mk_pdb()
|
||||
pdb.set_trace(
|
||||
# start 2 levels up in user code
|
||||
frame=sys._getframe().f_back.f_back,
|
||||
)
|
||||
|
@ -290,8 +290,10 @@ breakpoint = partial(
|
|||
|
||||
def _post_mortem(actor):
|
||||
log.critical(f"\nAttaching to pdb in crashed actor: {actor.uid}\n")
|
||||
pdb = _mk_pdb()
|
||||
|
||||
# custom Pdb post-mortem entry
|
||||
pdbpp.xpm(Pdb=PdbwTeardown)
|
||||
pdbpp.xpm(Pdb=lambda: pdb)
|
||||
|
||||
|
||||
post_mortem = partial(
|
||||
|
|
|
@ -7,7 +7,6 @@ import signal
|
|||
|
||||
import trio # type: ignore
|
||||
|
||||
from ._actor import Actor
|
||||
from .log import get_console_log, get_logger
|
||||
from . import _state
|
||||
|
||||
|
@ -16,7 +15,7 @@ log = get_logger(__name__)
|
|||
|
||||
|
||||
def _mp_main(
|
||||
actor: 'Actor',
|
||||
actor: 'Actor', # noqa
|
||||
accept_addr: Tuple[str, int],
|
||||
forkserver_info: Tuple[Any, Any, Any, Any, Any],
|
||||
start_method: str,
|
||||
|
@ -49,11 +48,13 @@ def _mp_main(
|
|||
trio.run(trio_main)
|
||||
except KeyboardInterrupt:
|
||||
pass # handle it the same way trio does?
|
||||
log.info(f"Actor {actor.uid} terminated")
|
||||
|
||||
finally:
|
||||
log.info(f"Actor {actor.uid} terminated")
|
||||
|
||||
|
||||
def _trio_main(
|
||||
actor: 'Actor',
|
||||
actor: 'Actor', # noqa
|
||||
parent_addr: Tuple[str, int] = None
|
||||
) -> None:
|
||||
"""Entry point for a `trio_run_in_process` subactor.
|
||||
|
@ -86,4 +87,5 @@ def _trio_main(
|
|||
except KeyboardInterrupt:
|
||||
log.warning(f"Actor {actor.uid} received KBI")
|
||||
|
||||
log.info(f"Actor {actor.uid} terminated")
|
||||
finally:
|
||||
log.info(f"Actor {actor.uid} terminated")
|
||||
|
|
Loading…
Reference in New Issue