WebSocket connection manager and broadcast
Managing WebSocket lifecycle and fan-out.
a manager class holding a list of active connections, connect accepts and appends, disconnect removes, broadcast iterates sending to each, all wrapped in try/finally to handle disconnects.
WHAT THIS TESTS Whether you understand the WebSocket lifecycle in FastAPI and can maintain shared mutable connection state, plus awareness that in-process state does not span workers.
A GOOD ANSWER COVERS Create a ConnectionManager class with self.active_connections as a list or set. Its async connect method awaits websocket.accept() then appends the socket. disconnect removes it. broadcast iterates the connections and awaits send_text or send_json on each, ideally guarding individual sends so one dead peer does not abort the loop. The WebSocket endpoint instantiates a shared manager (module-level), calls await manager.connect(ws), then loops awaiting ws.receive_text() inside a try block; on WebSocketDisconnect it calls manager.disconnect(ws) so the client is pruned. Wrapping cleanup in finally ensures removal even on unexpected errors. For correctness under concurrency you note that all this lives in one process: with multiple workers each holds a different subset of clients, so true broadcast across workers needs a shared message bus such as Redis pub/sub.
COMMON WRONG ANSWERS Never removing closed sockets, leaking memory and raising on send to dead clients. Forgetting to await accept(). Assuming a single in-memory list naturally reaches clients connected to other Uvicorn workers. Blocking the loop with synchronous work.
LIKELY FOLLOW-UPS How do you scale broadcast across multiple workers or servers? How do you handle backpressure to slow clients? How do you authenticate a WebSocket connection?
ONE CONCRETE EXAMPLE manager = ConnectionManager(); the endpoint does await manager.connect(ws); try: while True: data = await ws.receive_text(); await manager.broadcast(f'User: {data}') except WebSocketDisconnect: manager.disconnect(ws). broadcast does for c in self.active_connections: await c.send_text(message). To span two workers you replace the direct loop with publishing to a Redis channel each worker subscribes to.
Read the original → fastapi.tiangolo.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.