Stario 3.2.0: Writer.closing, tighter Writer.alive(), App.wait_shutdown() / app.shutting_down for tasks with no Writer. Datastar default + vendored bundle at v1.0.1.
Work queue
POST validates and Relay.publish commands; one long-lived GET owns the only Writer that writes that stream's body; a worker started with app.create_task subscribes and republishes (or drains a queue only that GET reads)—one coroutine touches Writer for that socket. Stream side: w.closing / w.alive(). Worker side: app.shutting_down / await app.wait_shutdown(); idle relays block on __anext__, so use asyncio.wait vs shutdown when you need SIGINT alone to unblock.
Declare the worker beside bootstrap, schedule once, pass relay into routers like chat-room build_chat_router(db, relay). Async-generator bootstrap with yield gives a teardown slice after shutdown starts (Runtime — lifecycle); plain async def bootstrap(...) -> None is the same wiring without that tail.
from collections.abc import AsyncIterator from stario import App, Relay, Span async def command_bridge(app: App, relay: Relay[str]) -> None: # async for on subscribe() registers for the whole loop (same as async with + for). async for topic, data in relay.subscribe("cmd.*"): relay.publish(f"stream:{topic}", f"applied:{data}") if app.shutting_down: break async def bootstrap(app: App, span: Span) -> AsyncIterator[None]: relay: Relay[str] = Relay() span.attr("relay", "control-plane") app.create_task(command_bridge(app, relay), name="cmd-bridge") app.mount("/", build_router(relay)) yield— Adam