Port `test_dynamic_pub_sub` off `run_in_actor`

The known-flaky dynamic pubsub test's 3 fire-and-forget spawn
sites (#477 removal),

- the forever-streaming `publisher` + N `consumer` one-shots now
  bg-schedule as `to_actor.run(fn, an=n)` tasks in a local `trio`
  task-nursery (`publisher`'s rendezvous name still derives from
  `fn.__name__`).
- the simulated user-cancel raise (`KeyboardInterrupt` /
  `TooSlowError` params) cancels the task-nursery, each one-shot
  reaping its subactor via `to_actor.run()`'s shielded
  `Portal.cancel_actor()`; `_run_and_match()`'s existing
  `BaseExceptionGroup.split()` walk covers the (possibly nested)
  relay shapes unchanged.
- spawns now issue concurrently rather than sequentially —
  comment on the fork-backend budget updated to match.

Gate: both params x4 runs green on `trio` + x1 on `mp_spawn`;
full module green.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
drop_ria_nursery
Gud Boi 2026-07-06 12:06:10 -04:00
parent f11754cecf
commit cb6202e3cb
1 changed files with 38 additions and 15 deletions

View File

@ -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,34 +215,56 @@ def test_dynamic_pub_sub(
f'enter `fail_after_w_trace({fail_after_s})` scope'
)
try:
async with tractor.open_nursery(
async with (
tractor.open_nursery(
registry_addrs=[reg_addr],
debug_mode=debug_mode,
) as n:
) 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(
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(
tn.start_soon(
partial(
tractor.to_actor.run,
consumer,
an=n,
name='consumer_dynamic',
subs=list(_registry.keys()),
)
)
# block until "cancelled by user"
await trio.sleep(3)