Websockets with multiple workers #8684
First Check
Commit to Help
Example Codefrom typing import List
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse
app = FastAPI()
html = """
<!DOCTYPE html>
<html>
<head>
<title>Chat</title>
</head>
<body>
<h1>WebSocket Chat</h1>
<h2>Your ID: <span id="ws-id"></span></h2>
<form action="" onsubmit="sendMessage(event)">
<input type="text" id="messageText" autocomplete="off"/>
<button>Send</button>
</form>
<ul id='messages'>
</ul>
<script>
var client_id = Date.now()
document.querySelector("#ws-id").textContent = client_id;
var ws = new WebSocket(`ws://localhost:8000/ws/${client_id}`);
ws.onmessage = function(event) {
var messages = document.getElementById('messages')
var message = document.createElement('li')
var content = document.createTextNode(event.data)
message.appendChild(content)
messages.appendChild(message)
};
function sendMessage(event) {
var input = document.getElementById("messageText")
ws.send(input.value)
input.value = ''
event.preventDefault()
}
</script>
</body>
</html>
"""
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 send_personal_message(self, message: str, websocket: WebSocket):
await websocket.send_text(message)
async def broadcast(self, message: str):
for connection in self.active_connections:
await connection.send_text(message)
manager = ConnectionManager()
@app.get("/")
async def get():
return HTMLResponse(html)
@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: int):
await manager.connect(websocket)
try:
while True:
data = await websocket.receive_text()
await manager.send_personal_message(f"You wrote: {data}", websocket)
await manager.broadcast(f"Client #{client_id} says: {data}")
except WebSocketDisconnect:
manager.disconnect(websocket)
await manager.broadcast(f"Client #{client_id} left the chat")DescriptionI'm using the example from FastAPI documentation for websockets, everything works fine while i have only 1 worker on my app, but when i set back 4 workers, seems that each worker has his own How can i manage websockets within multiple workers? Each time i save a connection on the Manager class, it seems to be saved only in one random app instance, no way to save it for each Operating SystemLinux Operating System DetailsNo response FastAPI Version0.68.1 Python Version3.9.4 Additional ContextNo response |
Replies: 7 comments 3 replies
|
You would have to find a way to communicate events between your workers - you might want to have a look at https://github.com/encode/broadcaster If you need something easy to integrate with FastAPI but that is more robust, supported by Redis, PostgreSQL or others, check encode/broadcaster." |
|
I have successfully implemented a FastAPI server with multiple workers and web sockets using Async socketio with redis for sharing between processes. https://pypi.org/project/fastapi-socketio/ If I remember correctly I had to tweak the library to allow for async but I can't remember exactly what I had to do. Sorry. Hope this is helpful. |
back to topic, has anyone ever found a solution to this? it's been almost 3 years and i still didn't manage to achieve this. |
|
no example on how to implement multiple workers with websocket? |
|
This is a very good write up on how to implement similar with Websockets and Redis Pub/Sub capabilities to allow horizontal scaling of application and worker servers. |
|
I just ran into this problem where I created a web socket manager class responsible for handling all the web sockets with unique identifier. |
You would have to find a way to communicate events between your workers - you might want to have a look at https://github.com/encode/broadcaster
It's mentioned in the docs @ https://fastapi.tiangolo.com/advanced/websockets/ :
"But have in mind that, as everything is handled in memory, in a single list, it will only work while the process is running, and will only work with a single process.
If you need something easy to integrate with FastAPI but that is more robust, supported by Redis, PostgreSQL or others, check encode/broadcaster."