"""Realtime fan-out over WebSocket. A single in-process connection manager broadcasts events/alerts to every connected browser. Run the API with a single worker so all sockets share this manager; for multi-worker scale put Redis pub/sub in front (see docs). """ from __future__ import annotations import asyncio from typing import Any from fastapi import WebSocket class ConnectionManager: def __init__(self) -> None: self._connections: set[WebSocket] = set() self._lock = asyncio.Lock() async def connect(self, ws: WebSocket) -> None: await ws.accept() async with self._lock: self._connections.add(ws) async def disconnect(self, ws: WebSocket) -> None: async with self._lock: self._connections.discard(ws) @property def count(self) -> int: return len(self._connections) async def broadcast(self, message: dict[str, Any]) -> None: if not self._connections: return async with self._lock: targets = list(self._connections) dead: list[WebSocket] = [] for ws in targets: try: await ws.send_json(message) except Exception: dead.append(ws) if dead: async with self._lock: for ws in dead: self._connections.discard(ws) manager = ConnectionManager() class StreamController: """Background task that emits mock logs at an interval until stopped.""" def __init__(self) -> None: self._task: asyncio.Task | None = None self.running = False self.rate = 3 # events per tick self.interval = 1.0 # seconds per tick self.profile = "mixed" def is_running(self) -> bool: return self.running and self._task is not None and not self._task.done() async def start(self, emit_coro, rate: int = 3, interval: float = 1.0, profile: str = "mixed") -> None: if self.is_running(): return self.rate, self.interval, self.profile = rate, interval, profile self.running = True self._task = asyncio.create_task(self._run(emit_coro)) async def _run(self, emit_coro) -> None: try: while self.running: await emit_coro(self.rate, self.profile) await asyncio.sleep(self.interval) except asyncio.CancelledError: pass finally: self.running = False async def stop(self) -> None: self.running = False if self._task: self._task.cancel() try: await self._task except asyncio.CancelledError: pass self._task = None stream = StreamController()