diff --git a/tractor/_portal.py b/tractor/_portal.py index e749ec6..af3c1b5 100644 --- a/tractor/_portal.py +++ b/tractor/_portal.py @@ -278,7 +278,8 @@ class Portal: try: # send cancel cmd - might not get response # XXX: sure would be nice to make this work with a proper shield - # with trio.CancelScope(shield=True): + # with trio.CancelScope() as cancel_scope: + # with trio.CancelScope(shield=True) as cancel_scope: with trio.move_on_after(0.5) as cancel_scope: cancel_scope.shield = True await self.run('self', 'cancel') diff --git a/tractor/_spawn.py b/tractor/_spawn.py index 6d19614..2a2f602 100644 --- a/tractor/_spawn.py +++ b/tractor/_spawn.py @@ -188,8 +188,17 @@ async def spawn_subactor( # the outer scope since no actor zombies are # ever allowed. This ``__aexit__()`` also shields # internally. - async with proc: - log.debug(f"Terminating {proc}") + log.debug(f"Attempting to kill {proc}") + + # NOTE: this timeout effectively does nothing right now since + # we are shielding the ``.wait()`` inside ``new_proc()`` which + # will pretty much never release until the process exits. + with trio.move_on_after(3) as cs: + async with proc: + log.debug(f"Terminating {proc}") + if cs.cancelled_caught: + log.critical(f"HARD KILLING {proc}") + proc.kill() async def new_proc( @@ -354,6 +363,8 @@ async def new_proc( await proc_waiter(proc) proc.join() + # This is again common logic for all backends: + log.debug(f"Joined {proc}") # pop child entry to indicate we are no longer managing this subactor subactor, proc, portal = actor_nursery._children.pop(subactor.uid)