Add per-actor parent-main replay opt-out
Let actor callers skip replaying the parent __main__ during child startup so downstream integrations can avoid inheriting incompatible bootstrap state without changing the default spawn behavior.subint_spawner_backend
parent
9f8e9eb739
commit
f5301d3fb0
|
|
@ -197,3 +197,50 @@ def test_loglevel_propagated_to_subactor(
|
|||
# ensure subactor spits log message on stderr
|
||||
captured = capfd.readouterr()
|
||||
assert 'yoyoyo' in captured.err
|
||||
|
||||
|
||||
def test_start_actor_can_skip_parent_main_replay(monkeypatch, reg_addr):
|
||||
captured_parent_main_data: list[dict[str, str]] = []
|
||||
from tractor.runtime import _supervise as supervise_module
|
||||
|
||||
async def fake_new_proc(
|
||||
name: str,
|
||||
actor_nursery,
|
||||
subactor,
|
||||
errors,
|
||||
bind_addrs,
|
||||
parent_addr,
|
||||
_runtime_vars,
|
||||
*,
|
||||
infect_asyncio: bool = False,
|
||||
task_status=trio.TASK_STATUS_IGNORED,
|
||||
proc_kwargs: dict[str, Any] = {},
|
||||
) -> None:
|
||||
captured_parent_main_data.append(dict(subactor._parent_main_data))
|
||||
task_status.started(object())
|
||||
|
||||
monkeypatch.setattr(
|
||||
supervise_module._spawn,
|
||||
'new_proc',
|
||||
fake_new_proc,
|
||||
)
|
||||
|
||||
async def main() -> None:
|
||||
async with tractor.open_root_actor(
|
||||
registry_addrs=[reg_addr],
|
||||
):
|
||||
async with tractor.open_nursery() as an:
|
||||
await an.start_actor(
|
||||
'replaying-parent-main',
|
||||
enable_modules=[__name__],
|
||||
)
|
||||
await an.start_actor(
|
||||
'isolated-parent-main',
|
||||
enable_modules=[__name__],
|
||||
replay_parent_main=False,
|
||||
)
|
||||
|
||||
trio.run(main)
|
||||
|
||||
assert captured_parent_main_data[0]
|
||||
assert captured_parent_main_data[1] == {}
|
||||
|
|
|
|||
|
|
@ -194,6 +194,7 @@ class ActorNursery:
|
|||
loglevel: str|None = None, # set log level per subactor
|
||||
debug_mode: bool|None = None,
|
||||
infect_asyncio: bool = False,
|
||||
replay_parent_main: bool = True,
|
||||
|
||||
# TODO: ideally we can rm this once we no longer have
|
||||
# a `._ria_nursery` since the dependent APIs have been
|
||||
|
|
@ -206,6 +207,10 @@ class ActorNursery:
|
|||
Start a (daemon) actor: an process that has no designated
|
||||
"main task" besides the runtime.
|
||||
|
||||
Pass ``replay_parent_main=False`` to keep this child on its own
|
||||
bootstrap module instead of re-running the parent's ``__main__``
|
||||
during startup.
|
||||
|
||||
'''
|
||||
__runtimeframe__: int = 1 # noqa
|
||||
loglevel: str = (
|
||||
|
|
@ -246,6 +251,8 @@ class ActorNursery:
|
|||
# verbatim relay this actor's registrar addresses
|
||||
registry_addrs=current_actor().registry_addrs,
|
||||
)
|
||||
if not replay_parent_main:
|
||||
subactor._parent_main_data = {}
|
||||
parent_addr: UnwrappedAddress = self._actor.accept_addr
|
||||
assert parent_addr
|
||||
|
||||
|
|
@ -289,6 +296,7 @@ class ActorNursery:
|
|||
enable_modules: list[str] | None = None,
|
||||
loglevel: str | None = None, # set log level per subactor
|
||||
infect_asyncio: bool = False,
|
||||
replay_parent_main: bool = True,
|
||||
proc_kwargs: dict[str, any] = {},
|
||||
|
||||
**kwargs, # explicit args to ``fn``
|
||||
|
|
@ -320,6 +328,7 @@ class ActorNursery:
|
|||
# use the run_in_actor nursery
|
||||
nursery=self._ria_nursery,
|
||||
infect_asyncio=infect_asyncio,
|
||||
replay_parent_main=replay_parent_main,
|
||||
proc_kwargs=proc_kwargs
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue