From 93f70c63a4c7b91098aa28e6d48e4109fc0cd07b Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Tue, 17 Jun 2025 11:33:36 -0400 Subject: [PATCH] Use `enable_transports: list[str]` parameter Actually applying the input it in the root as well as all sub-actors by passing it down to sub-actors through runtime-vars as delivered by the initial `SpawnSpec` msg during child runtime init. Impl deats, - add a new `_state._runtime_vars['_enable_tpts']: list[str]` field set by the input param (if provided) to `.open_root_actor()`. - mk `current_ipc_protos()` return the runtime-var entry with instead the default in the `_runtime_vars: dict` set to `[_def_tpt_proto]`. - in `.open_root_actor()`, still error on this being a >1 `list[str]` until we have more testing infra/suites to audit multi-protos per actor. - return the new value (as 3rd element) from `Actor._from_parent()` as per the todo note; means `_runtime.async_main()` will allocate `accept_addrs` as tpt-specific `Address` entries and pass them to `IPCServer.listen_on()`. Also, - also add a new `_state._runtime_vars['_root_addrs']: list = []` field with the intent of fully replacing the `'_root_mailbox'` field since, * it will need to be a collection to support multi-tpt, * it's a more cohesive field name alongside `_registry_addrs`, * the root actor of every tree needs to have a dedicated addr set (separate from any host-singleton registry actor) so that all its subs can contact it for capabilities mgmt including debugger access/locking. - in the root, populate the field in `._runtime.async_main()` and for now just set '_root_mailbox' to the first entry in that list in anticipation of future multi-homing/transport support. --- tractor/_root.py | 13 +++++++++---- tractor/_runtime.py | 10 +++++----- tractor/_state.py | 21 ++++++++++++--------- tractor/msg/types.py | 1 + 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/tractor/_root.py b/tractor/_root.py index 504cf247..e9c35f7f 100644 --- a/tractor/_root.py +++ b/tractor/_root.py @@ -224,11 +224,16 @@ async def open_root_actor( ): if enable_transports is None: enable_transports: list[str] = _state.current_ipc_protos() + else: + _state._runtime_vars['_enable_tpts'] = enable_transports - # TODO! support multi-tpts per actor! Bo - assert ( - len(enable_transports) == 1 - ), 'No multi-tpt support yet!' + # TODO! support multi-tpts per actor! + # Bo + if not len(enable_transports) == 1: + raise RuntimeError( + f'No multi-tpt support yet!\n' + f'enable_transports={enable_transports!r}\n' + ) _frame_stack.hide_runtime_frames() __tracebackhide__: bool = hide_tb diff --git a/tractor/_runtime.py b/tractor/_runtime.py index 1e51a469..2f9749a2 100644 --- a/tractor/_runtime.py +++ b/tractor/_runtime.py @@ -914,9 +914,7 @@ class Actor: return ( chan, accept_addrs, - None, - # ^TODO, preferred tpts list from rent! - # -[ ] need to extend the `SpawnSpec` tho! + _state._runtime_vars['_enable_tpts'] ) # failed to connect back? @@ -1496,10 +1494,12 @@ async def async_main( # all sub-actors should be able to speak to # their root actor over that channel. if _state._runtime_vars['_is_root']: + raddrs: list[Address] = _state._runtime_vars['_root_addrs'] for addr in accept_addrs: waddr: Address = wrap_address(addr) - if waddr == waddr.get_root(): - _state._runtime_vars['_root_mailbox'] = addr + raddrs.append(addr) + else: + _state._runtime_vars['_root_mailbox'] = raddrs[0] # Register with the arbiter if we're told its addr log.runtime( diff --git a/tractor/_state.py b/tractor/_state.py index 30ccff3d..2a47e548 100644 --- a/tractor/_state.py +++ b/tractor/_state.py @@ -37,6 +37,13 @@ if TYPE_CHECKING: from ._context import Context +# default IPC transport protocol settings +TransportProtocolKey = Literal[ + 'tcp', + 'uds', +] +_def_tpt_proto: TransportProtocolKey = 'tcp' + _current_actor: Actor|None = None # type: ignore # noqa _last_actor_terminated: Actor|None = None @@ -47,6 +54,10 @@ _runtime_vars: dict[str, Any] = { # root of actor-process tree info '_is_root': False, # bool '_root_mailbox': (None, None), # tuple[str|None, str|None] + '_root_addrs': [], # tuple[str|None, str|None] + + # parent->chld ipc protocol caps + '_enable_tpts': [_def_tpt_proto], # registrar info '_registry_addrs': [], @@ -180,14 +191,6 @@ def get_rt_dir( return rtdir -# default IPC transport protocol settings -TransportProtocolKey = Literal[ - 'tcp', - 'uds', -] -_def_tpt_proto: TransportProtocolKey = 'tcp' - - def current_ipc_protos() -> list[str]: ''' Return the list of IPC transport protocol keys currently @@ -197,4 +200,4 @@ def current_ipc_protos() -> list[str]: concrete-backend sub-types defined throughout `tractor.ipc`. ''' - return [_def_tpt_proto] + return _runtime_vars['_enable_tpts'] diff --git a/tractor/msg/types.py b/tractor/msg/types.py index 86752aba..aaf8d137 100644 --- a/tractor/msg/types.py +++ b/tractor/msg/types.py @@ -170,6 +170,7 @@ class SpawnSpec( # a hard `Struct` def for all of these fields! _parent_main_data: dict _runtime_vars: dict[str, Any] + # ^NOTE see `._state._runtime_vars: dict` # module import capability enable_modules: dict[str, str]