From 44d730c7235be23f3811474cd8bd98ec434afb1c Mon Sep 17 00:00:00 2001 From: goodboy Date: Thu, 2 Jul 2026 23:57:59 -0400 Subject: [PATCH] Port `test_pubsub` off `run_in_actor` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `test_multi_actor_subs_arbiter_pub` used `run_in_actor()` to spawn two forever-ish subscriber actors and hold their portals for a later `cancel_actor()` (its `.result()` was commented out exactly because `subs()` never cleanly returns). That deferred-spawn + cancel shape isn't a blocking `to_actor.run()`, so convert to the successor primitives (#477 removal), - `start_actor()` per subscriber — keeps the portal for the existing `cancel_actor()` teardown, - run `subs()` on each via a background `Portal.run()` task in a local `trio` nursery so both subscribe concurrently with the test's `wait_for_actor` / topic checks, - each bg runner swallows the `RemoteActorError`/`ContextCancelled` that `cancel_actor()` relays; a trailing `tn.cancel_scope.cancel()` drops any lingering runner. Suite: 8 passed. (this patch was generated in some part by [`claude-code`][claude-code-gh]) [claude-code-gh]: https://github.com/anthropics/claude-code --- tests/test_pubsub.py | 53 ++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/tests/test_pubsub.py b/tests/test_pubsub.py index 1bf8563a..550ac4e1 100644 --- a/tests/test_pubsub.py +++ b/tests/test_pubsub.py @@ -176,10 +176,13 @@ def test_multi_actor_subs_arbiter_pub( async def main(): - async with tractor.open_nursery( - registry_addrs=[reg_addr], - enable_modules=[__name__], - ) as n: + async with ( + tractor.open_nursery( + registry_addrs=[reg_addr], + enable_modules=[__name__], + ) as n, + trio.open_nursery() as tn, + ): name = 'root' @@ -191,18 +194,37 @@ def test_multi_actor_subs_arbiter_pub( ) name = 'streamer' - even_portal = await n.run_in_actor( - subs, - which=['even'], - name='evens', - pub_actor_name=name + # spawn the two subscriber actors as daemons and run + # `subs()` on each as a background task (was the legacy + # `run_in_actor()`); keep the portals for the explicit + # `cancel_actor()` teardown below. Each runner swallows + # the teardown error that `cancel_actor()` relays. + async def _run_subs( + portal: tractor.Portal, + which: list[str], + ) -> None: + try: + await portal.run( + subs, + which=which, + pub_actor_name=name, + ) + except ( + tractor.RemoteActorError, + tractor.ContextCancelled, + ): + pass # expected once we `cancel_actor()` below + + even_portal = await n.start_actor( + 'evens', + enable_modules=[__name__], ) - odd_portal = await n.run_in_actor( - subs, - which=['odd'], - name='odds', - pub_actor_name=name + odd_portal = await n.start_actor( + 'odds', + enable_modules=[__name__], ) + tn.start_soon(_run_subs, even_portal, ['even']) + tn.start_soon(_run_subs, odd_portal, ['odd']) async with tractor.wait_for_actor('evens'): # block until 2nd actor is initialized @@ -257,6 +279,9 @@ def test_multi_actor_subs_arbiter_pub( else: await master_portal.cancel_actor() + # drop the bg `subs()` runners now the subs are cancelled + tn.cancel_scope.cancel() + trio.run(main)