diff --git a/tests/test_advanced_streaming.py b/tests/test_advanced_streaming.py index 3e9fa3f5..6baa855a 100644 --- a/tests/test_advanced_streaming.py +++ b/tests/test_advanced_streaming.py @@ -3,6 +3,7 @@ Advanced streaming patterns using bidirectional streams and contexts. ''' from collections import Counter +from functools import partial import itertools import platform from typing import Type @@ -173,8 +174,8 @@ def test_dynamic_pub_sub( # test. Picked backend-aware: under `trio` backend spawn is # cheap (~1s for `cpus` actors) but fork-based backends pay # a per-spawn cost (forkserver round-trip + IPC peer-handshake) - # that can stack up over `cpus - 1` sequential `n.run_in_actor()` - # calls — especially on UDS under cross-pytest contention + # that can stack up over the `cpus - 1` one-shot + # (`to_actor.run()`) spawns — especially on UDS under cross-pytest contention # (#451 / #452). 4s was flaking right at the edge under fork # backends — bumped to 8s with diag-snapshot-on-timeout via # `fail_after_w_trace` so a borderline run still fails loud @@ -214,33 +215,55 @@ def test_dynamic_pub_sub( f'enter `fail_after_w_trace({fail_after_s})` scope' ) try: - async with tractor.open_nursery( - registry_addrs=[reg_addr], - debug_mode=debug_mode, - ) as n: + async with ( + tractor.open_nursery( + registry_addrs=[reg_addr], + debug_mode=debug_mode, + ) as n, + # bg-schedules the forever-streaming + # one-shots below; the user-cancel raise + # cancels them all, each reaping its + # subactor via `to_actor.run()`'s + # (shielded) `Portal.cancel_actor()`. + trio.open_nursery() as tn, + ): test_log.cancel( 'test_dynamic_pub_sub: ' 'actor nursery opened' ) # name of this actor will be same as target func - await n.run_in_actor(publisher) + tn.start_soon( + partial( + tractor.to_actor.run, + publisher, + an=n, + ) + ) for i, sub in zip( range(cpus - 2), itertools.cycle(_registry.keys()) ): - await n.run_in_actor( - consumer, - name=f'consumer_{sub}', - subs=[sub], + tn.start_soon( + partial( + tractor.to_actor.run, + consumer, + an=n, + name=f'consumer_{sub}', + subs=[sub], + ) ) # make one dynamic subscriber - await n.run_in_actor( - consumer, - name='consumer_dynamic', - subs=list(_registry.keys()), + tn.start_soon( + partial( + tractor.to_actor.run, + consumer, + an=n, + name='consumer_dynamic', + subs=list(_registry.keys()), + ) ) # block until "cancelled by user"