forked from goodboy/tractor
Don't kill root's immediate children when in debug
If the root calls `trio.Process.kill()` on immediate child proc teardown when the child is using pdb, we can get stdstreams clobbering that results in a pdb++ repl where the user can't see what's been typed. Not killing such children on cancellation / error seems to resolve this issue whilst still giving reliable termination. For now, code that special path until a time it becomes a problem for ensuring zombie reaps.CI_increment_for_windows_bidirstreaming
parent
f69229b11a
commit
f30fdae328
|
@ -25,7 +25,10 @@ from . import _forkserver_override
|
|||
from ._state import (
|
||||
current_actor,
|
||||
is_main_process,
|
||||
is_root_process,
|
||||
_runtime_vars,
|
||||
)
|
||||
|
||||
from .log import get_logger
|
||||
from ._portal import Portal
|
||||
from ._actor import Actor, ActorFailure
|
||||
|
@ -206,13 +209,46 @@ async def spawn_subactor(
|
|||
yield proc
|
||||
|
||||
finally:
|
||||
log.debug(f"Attempting to kill {proc}")
|
||||
|
||||
# XXX: do this **after** cancellation/tearfown
|
||||
# to avoid killing the process too early
|
||||
# since trio does this internally on ``__aexit__()``
|
||||
|
||||
log.debug(f"Attempting to kill {proc}")
|
||||
await do_hard_kill(proc)
|
||||
if (
|
||||
is_root_process()
|
||||
|
||||
# XXX: basically the pre-closing of stdstreams in a
|
||||
# root-processe's ``trio.Process.aclose()`` can clobber
|
||||
# any existing debugger session so we avoid
|
||||
and _runtime_vars['_debug_mode']
|
||||
):
|
||||
# XXX: this is ``trio.Process.aclose()`` minus
|
||||
# the std-streams pre-closing steps and ``Process.kill()``
|
||||
# calls.
|
||||
try:
|
||||
await proc.wait()
|
||||
finally:
|
||||
if proc.returncode is None:
|
||||
# XXX: skip this when in debug and a session might
|
||||
# still be live
|
||||
# proc.kill()
|
||||
with trio.CancelScope(shield=True):
|
||||
await proc.wait()
|
||||
else:
|
||||
# NOTE: this timeout used to do nothing since we were shielding
|
||||
# the ``.wait()`` inside ``new_proc()`` which will pretty much
|
||||
# never release until the process exits, now it acts as
|
||||
# a hard-kill time ultimatum.
|
||||
with trio.move_on_after(3) as cs:
|
||||
|
||||
# NOTE: This ``__aexit__()`` shields internally.
|
||||
async with proc: # calls ``trio.Process.aclose()``
|
||||
log.debug(f"Terminating {proc}")
|
||||
|
||||
if cs.cancelled_caught:
|
||||
log.critical(f"HARD KILLING {proc}")
|
||||
proc.kill()
|
||||
|
||||
|
||||
async def new_proc(
|
||||
|
|
Loading…
Reference in New Issue