Wait for active pub/sub cancellation targets

Replace `test_dynamic_pub_sub()`'s fixed startup sleep with an RPC
activity probe in the publisher actor. Track the publisher task and
wait until every launched consumer has installed its first
subscription before raising the user cancellation exception.

This keeps slow spawn backends from passing the regression by
cancelling actors which never reached the streaming workload.

Review: PR #484 (OpenCode)
https://github.com/goodboy/tractor/pull/484#pullrequestreview-5025383596

(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
drop_ria_nursery
Gud Boi 2026-08-25 20:23:53 -04:00
parent 266073cb69
commit dd3e7482bf
1 changed files with 41 additions and 10 deletions

View File

@ -25,6 +25,7 @@ _registry: dict[str, set[tractor.MsgStream]] = {
'even': set(), 'even': set(),
'odd': set(), 'odd': set(),
} }
_publisher_started: bool = False
async def publisher( async def publisher(
@ -33,11 +34,13 @@ async def publisher(
) -> None: ) -> None:
global _registry global _publisher_started, _registry
def is_even(i): def is_even(i):
return i % 2 == 0 return i % 2 == 0
_publisher_started = True
try:
for val in itertools.count(seed): for val in itertools.count(seed):
sub = 'even' if is_even(val) else 'odd' sub = 'even' if is_even(val) else 'odd'
@ -49,6 +52,26 @@ async def publisher(
# making it readable to a human user # making it readable to a human user
await trio.sleep(1/1000) await trio.sleep(1/1000)
finally:
_publisher_started = False
async def pubsub_active(
expected_subs: int,
) -> bool:
'''
Report whether the publisher and all subscriber tasks are active.
Runs as an RPC task in the publisher actor, where `_registry` is
mutated by each `subscribe()` context after its consumer sends the
first subscription.
'''
return (
_publisher_started
and sum(map(len, _registry.values())) >= expected_subs
)
@tractor.context @tractor.context
async def subscribe( async def subscribe(
@ -270,8 +293,16 @@ def test_dynamic_pub_sub(
) )
) )
# block until "cancelled by user" expected_subs: int = max(cpus - 2, 0) + 1
await trio.sleep(3) async with tractor.wait_for_actor(
'publisher',
) as portal:
while not await portal.run(
pubsub_active,
expected_subs=expected_subs,
):
await trio.sleep(0.01)
test_log.warning( test_log.warning(
f'Raising user cancel exc: ' f'Raising user cancel exc: '
f'{expect_cancel_exc!r}' f'{expect_cancel_exc!r}'