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