From d6ca4771ce7d9e5137db030d2179d3fc395464e3 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Thu, 9 May 2024 09:37:47 -0400 Subject: [PATCH] Use `.recv_msg_w_pld()` for final `Portal.result()` Woops, due to a `None` test against the `._final_result`, any actual final `None` result would be received but not acked as such causing a spawning test to hang. Fix it by instead receiving and assigning both a `._final_result_msg: PayloadMsg` and `._final_result_pld`. NB: as mentioned in many recent comments surrounding this API layer, really this whole `Portal`-has-final-result interface/semantics should be entirely removed as should the `ActorNursery.run_in_actor()` API(s). Instead it should all be replaced by a wrapping "high level" API (`tractor.hilevel` ?) which combines a task nursery, `Portal.open_context()` and underlying `Context` APIs + an `outcome.Outcome` to accomplish the same "run a single task in a spawned actor and return it's result"; aka a "one-shot-task-actor". --- tractor/_portal.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tractor/_portal.py b/tractor/_portal.py index 79a9dc5..700f2fd 100644 --- a/tractor/_portal.py +++ b/tractor/_portal.py @@ -47,6 +47,7 @@ from ._ipc import Channel from .log import get_logger from .msg import ( # Error, + PayloadMsg, NamespacePath, Return, ) @@ -98,7 +99,8 @@ class Portal: self.chan = channel # during the portal's lifetime - self._final_result: Any|None = None + self._final_result_pld: Any|None = None + self._final_result_msg: PayloadMsg|None = None # When set to a ``Context`` (when _submit_for_result is called) # it is expected that ``result()`` will be awaited at some @@ -132,7 +134,7 @@ class Portal: 'A pending main result has already been submitted' ) - self._expect_result_ctx = await self.actor.start_remote_task( + self._expect_result_ctx: Context = await self.actor.start_remote_task( self.channel, nsf=NamespacePath(f'{ns}:{func}'), kwargs=kwargs, @@ -163,13 +165,16 @@ class Portal: # expecting a "main" result assert self._expect_result_ctx - if self._final_result is None: - self._final_result: Any = await self._expect_result_ctx._pld_rx.recv_pld( - ctx=self._expect_result_ctx, + if self._final_result_msg is None: + ( + self._final_result_msg, + self._final_result_pld, + ) = await self._expect_result_ctx._pld_rx.recv_msg_w_pld( + ipc=self._expect_result_ctx, expect_msg=Return, ) - return self._final_result + return self._final_result_pld async def _cancel_streams(self): # terminate all locally running async generator