From dc806b8aba69b8ab3aef8310a7be9a65f68174ac Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Mon, 4 Aug 2025 14:35:09 -0400 Subject: [PATCH] Add `ActorCancelled` as an runtime-wide-signal As in a layer "above" a KBI/SIGINT but "below" a `ContextCancelled` and generally signalling an interrupt which requests cancellation of the actor's `trio.run()`. Impl deats, - mk the new exc type inherit from our ctxc (for now) but overriding the `.canceller` impl to, * pull from the `RemoteActorError._extra_msgdata: dict` when no `._ipc_msg` is set (which is always to start, until we incorporate a new `CancelActor` msg type). * not allow a `None` value since we should key-error if not set per prev bullet. - Mk adjustments (related) to parent `RemoteActorError.pformat()` to accommodate showing the `.canceller` field in repr output, * change `.relay_uid` to not crash when `._ipc_msg` is unset. * support `.msg.types.Aid` and use its `.reprol()` from `._mk_fields_str()`. * always call `._mk_fields_str()`, not just when `tb_str` is provided, and for now use any `._message` in-place of a `tb_str` when undefined. --- tractor/_exceptions.py | 124 ++++++++++++++++++++++++++++++++--------- 1 file changed, 99 insertions(+), 25 deletions(-) diff --git a/tractor/_exceptions.py b/tractor/_exceptions.py index 418accc3..3c469222 100644 --- a/tractor/_exceptions.py +++ b/tractor/_exceptions.py @@ -46,6 +46,7 @@ from msgspec import ( from tractor._state import current_actor from tractor.log import get_logger from tractor.msg import ( + Aid, Error, PayloadMsg, MsgType, @@ -479,9 +480,10 @@ class RemoteActorError(Exception): @property def relay_uid(self) -> tuple[str, str]|None: - return tuple( - self._ipc_msg.relay_path[-1] - ) + if msg := self._ipc_msg: + return tuple( + msg.relay_path[-1] + ) @property def src_uid(self) -> tuple[str, str]|None: @@ -521,7 +523,8 @@ class RemoteActorError(Exception): for key in fields: if ( key == 'relay_uid' - and not self.is_inception() + and + not self.is_inception() ): continue @@ -534,6 +537,13 @@ class RemoteActorError(Exception): None, ) ) + if ( + key == 'canceller' + and + isinstance(val, Aid) + ): + val: str = val.reprol(sin_uuid=False) + # TODO: for `.relay_path` on multiline? # if not isinstance(val, str): # val_str = pformat(val) @@ -623,25 +633,32 @@ class RemoteActorError(Exception): # IFF there is an embedded traceback-str we always # draw the ascii-box around it. body: str = '' - if tb_str := self.tb_str: - fields: str = self._mk_fields_str( - _body_fields - + - self.extra_body_fields, - ) - from tractor.devx import ( - pformat_boxed_tb, - ) - body: str = pformat_boxed_tb( - tb_str=tb_str, - fields_str=fields, - field_prefix=' |_', - # ^- is so that it's placed like so, - # just after Aid: + ''' + Return the (maybe) `Actor.aid: Aid` for the requesting-author + of this actorc. + + Emit a warning msg when `.canceller` has not been set. + + See additional relevant notes in + `ContextCancelled.canceller`. + + ''' + value: tuple[str, str]|None + if msg := self._ipc_msg: + value = msg.canceller + else: + value = self._extra_msgdata['canceller'] + + if value: + return value + + log.warning( + 'IPC Context cancelled without a requesting actor?\n' + 'Maybe the IPC transport ended abruptly?\n\n' + f'{self}' + ) + + class MsgTypeError( RemoteActorError, ):