forked from goodboy/tractor
Add `Actor.cancel_soon()` for sync self destruct
Add a sync method that can be used to cancel the current actor from a synchronous context. This is useful in debugging situations where sync debugger code may need to kill the process tree. Also, make the internal "lifetime stack" a global var; easier to manage from client code that may was to add callbacks prior to the actor runtime being fully setup.advanced_debugger_testing
parent
2674c54c0b
commit
5f55c7ca00
|
@ -162,6 +162,10 @@ def _get_mod_abspath(module):
|
||||||
return os.path.abspath(module.__file__)
|
return os.path.abspath(module.__file__)
|
||||||
|
|
||||||
|
|
||||||
|
# process-global stack closed at end on actor runtime teardown
|
||||||
|
_lifetime_stack: ExitStack = ExitStack()
|
||||||
|
|
||||||
|
|
||||||
class Actor:
|
class Actor:
|
||||||
"""The fundamental concurrency primitive.
|
"""The fundamental concurrency primitive.
|
||||||
|
|
||||||
|
@ -176,7 +180,6 @@ class Actor:
|
||||||
_root_n: Optional[trio.Nursery] = None
|
_root_n: Optional[trio.Nursery] = None
|
||||||
_service_n: Optional[trio.Nursery] = None
|
_service_n: Optional[trio.Nursery] = None
|
||||||
_server_n: Optional[trio.Nursery] = None
|
_server_n: Optional[trio.Nursery] = None
|
||||||
_lifetime_stack: ExitStack = ExitStack()
|
|
||||||
|
|
||||||
# Information about `__main__` from parent
|
# Information about `__main__` from parent
|
||||||
_parent_main_data: Dict[str, str]
|
_parent_main_data: Dict[str, str]
|
||||||
|
@ -531,8 +534,9 @@ class Actor:
|
||||||
# deadlock and other weird behaviour)
|
# deadlock and other weird behaviour)
|
||||||
if func != self.cancel:
|
if func != self.cancel:
|
||||||
if isinstance(cs, Exception):
|
if isinstance(cs, Exception):
|
||||||
log.warning(f"Task for RPC func {func} failed with"
|
log.warning(
|
||||||
f"{cs}")
|
f"Task for RPC func {func} failed with"
|
||||||
|
f"{cs}")
|
||||||
else:
|
else:
|
||||||
# mark that we have ongoing rpc tasks
|
# mark that we have ongoing rpc tasks
|
||||||
self._ongoing_rpc_tasks = trio.Event()
|
self._ongoing_rpc_tasks = trio.Event()
|
||||||
|
@ -770,7 +774,7 @@ class Actor:
|
||||||
# tear down all lifetime contexts
|
# tear down all lifetime contexts
|
||||||
# api idea: ``tractor.open_context()``
|
# api idea: ``tractor.open_context()``
|
||||||
log.warning("Closing all actor lifetime contexts")
|
log.warning("Closing all actor lifetime contexts")
|
||||||
self._lifetime_stack.close()
|
_lifetime_stack.close()
|
||||||
|
|
||||||
# Unregister actor from the arbiter
|
# Unregister actor from the arbiter
|
||||||
if registered_with_arbiter and (
|
if registered_with_arbiter and (
|
||||||
|
@ -840,6 +844,14 @@ class Actor:
|
||||||
# signal the server is down since nursery above terminated
|
# signal the server is down since nursery above terminated
|
||||||
self._server_down.set()
|
self._server_down.set()
|
||||||
|
|
||||||
|
def cancel_soon(self) -> None:
|
||||||
|
"""Cancel this actor asap; can be called from a sync context.
|
||||||
|
|
||||||
|
Schedules `.cancel()` to be run immediately just like when
|
||||||
|
cancelled by the parent.
|
||||||
|
"""
|
||||||
|
self._service_n.start_soon(self.cancel)
|
||||||
|
|
||||||
async def cancel(self) -> bool:
|
async def cancel(self) -> bool:
|
||||||
"""Cancel this actor.
|
"""Cancel this actor.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue