WebSocket Rooms & Broadcasting
Learn the connection manager pattern to manage multiple WebSocket clients and broadcast messages to all connected users.
🎯 What You'll Learn
- •Implement a ConnectionManager class for managing WebSocket connections
- •Track active connections and handle connect/disconnect events
- •Broadcast messages to all connected clients simultaneously
- •Use client IDs to identify individual WebSocket connections
WebSocket Rooms & Broadcasting
What You'll Learn
In this lesson you will learn how to manage multiple WebSocket connections and broadcast messages to all connected clients. You will understand:
- The ConnectionManager pattern for tracking active WebSocket connections
- How to broadcast messages to all connected clients simultaneously
- How to identify clients using path parameters
- How to handle connect and disconnect events cleanly
Theory
The Problem: Multiple Clients
A basic WebSocket echo server handles one connection at a time. But real applications need to manage many clients simultaneously:
- A chat room where messages from one user appear for everyone
- A live dashboard that pushes updates to all viewers
- A multiplayer game that syncs state across players
To manage this, we use the ConnectionManager pattern.
The ConnectionManager Pattern
A ConnectionManager is a class that keeps track of all active WebSocket connections and provides methods to manage them:
from fastapi import WebSocket
class ConnectionManager:
def __init__(self):
self.active_connections: list[WebSocket] = []
async def connect(self, websocket: WebSocket):
await websocket.accept()
self.active_connections.append(websocket)
def disconnect(self, websocket: WebSocket):
self.active_connections.remove(websocket)
async def broadcast(self, message: str):
for connection in self.active_connections:
await connection.send_text(message)
This centralizes all connection logic in one place, making it easy to manage and extend.
Using the ConnectionManager
Create a single instance and use it in your WebSocket endpoint:
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
app = FastAPI()
manager = ConnectionManager()
@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: str):
await manager.connect(websocket)
await manager.broadcast(f"Client #{client_id} joined")
try:
while True:
data = await websocket.receive_text()
await manager.broadcast(f"Client #{client_id}: {data}")
except WebSocketDisconnect:
manager.disconnect(websocket)
await manager.broadcast(f"Client #{client_id} left")
Client Identification
Using path parameters like /ws/{client_id} lets you identify who sent each message. The client_id can be:
- A username
- A session token
- A room identifier
- Any unique string the client provides
Connection Lifecycle with Manager
The flow for each client connection:
- Client connects to
/ws/{client_id} - Manager accepts the connection and adds it to the list
- A "joined" broadcast notifies all other clients
- Messages from this client are broadcast to everyone
- On disconnect, the connection is removed from the list
- A "left" broadcast notifies remaining clients
Sending to Specific Clients
You can extend the manager to send messages to specific clients instead of broadcasting:
class ConnectionManager:
def __init__(self):
self.active_connections: dict[str, WebSocket] = {}
async def connect(self, client_id: str, websocket: WebSocket):
await websocket.accept()
self.active_connections[client_id] = websocket
def disconnect(self, client_id: str):
del self.active_connections[client_id]
async def send_personal(self, client_id: str, message: str):
websocket = self.active_connections.get(client_id)
if websocket:
await websocket.send_text(message)
async def broadcast(self, message: str):
for websocket in self.active_connections.values():
await websocket.send_text(message)
This version uses a dictionary keyed by client_id, allowing targeted messaging.
Key Concepts
- ConnectionManager: A class that tracks and manages all active WebSocket connections
- active_connections: A list (or dict) storing all currently connected WebSocket objects
- connect(): Accepts the WebSocket and adds it to the tracked connections
- disconnect(): Removes a WebSocket from the tracked connections
- broadcast(): Sends a message to every active connection
- Client ID: A path parameter used to identify individual WebSocket clients
- Graceful disconnect: Removing the connection and notifying others when a client leaves
Best Practices
- Use a single manager instance shared across all WebSocket endpoints
- Always remove connections on disconnect to avoid sending to closed sockets
- Handle errors during broadcast -- if one
send_textfails, catch the exception so other clients still receive the message - Use dictionaries for client lookup when you need to send messages to specific clients
- Keep broadcast messages small -- sending large payloads to many clients can cause performance issues
- Consider connection limits -- in production, limit the number of active connections to prevent resource exhaustion
- Add authentication -- validate client identity before accepting the WebSocket connection
Additional Resources
💡 Hint
Create a ConnectionManager class with a list of active_connections. Implement connect (append + accept), disconnect (remove), and broadcast (loop and send) methods. Use it in a '/ws/{client_id}' endpoint.
Ready to Practice?
Now that you understand the theory, let's put it into practice with hands-on coding!
Start Interactive Lesson