I've implemented a website chat with python-socketio and socket.io-client.
At times, when we simultaneously open multiple tabs in different browsers or incognito sessions with the same logged-in user, the newly opened tabs can successfully send and receive messages. However, the older tabs CAN send but DO NOT receive messages, even though they remain connected to Python Socket.IO and socket.io-client. Additionally, I've already used a room session for managing the connections. This Problem happens on a live server where, at any point about 50-100 users are connected to the socket, not on localhost.
The versions I'm using are as follows:
python-socketio==5.9.0
uvicorn==0.16.0
eventlet==0.33.3
socket.io-client = 4.7.2
Backend:
import socketio
sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins='*', logger=True, engineio_logger=True)
connected_users = {}
room_user_count = {}
@sio.on("connect")
async def connect(sid, environ):
try:
query_string = environ.get("QUERY_STRING") or "Anonymous"
if query_string:
username = query_string.split("username=")[1].split("&")[0]
await sio.save_session(sid, {'username': username})
room_name = await change_group_name(username)
sio.enter_room(sid, room_name)
print(f"[Connected] {sid}")
except Exception as e:
print("Connected error", str(e))
@sio.on("login")
async def handle_login(sid, data):
username = data.get("username")
session_id = await sio.get_session(sid)
connected_users[sid] = {"username": username, "session_id": session_id['username']}
print(f"{username} logged in.")
@sio.on("disconnect")
async def disconnect(sid):
try:
username = connected_users.get(sid, {}).get("username", "Anonymous")
connected_users.pop(sid, None)
leave_room = await change_group_name(username)
sio.leave_room(sid, leave_room)
print(f"Disconnected: {sid}, Username: {username}")
except Exception as e:
print(f"Disconnected Error: {e}")
@sio.on("client_chat_app")
async def message_from_client(sid, data):
username = connected_users.get(sid, {}).get("username", "Anonymous")
user = await get_user_obj(username)
await chat_app_function(data, user, sid)
Frontend:
import socketIOClient from "socket.io-client";
useEffect(() => {
let username = “username”;
socket = socketIOClient(WEB_SOCKET_IO, {
query: { username: username },
secure: true,
transports: ["websocket"],
path: "/socket.io/",
reconnectionDelay: 1000,
reconnection: true,
reconnectionAttempts: Infinity,
});
socket.on("connect", () => {
socket.emit("login", { username });
});
let event_chat_app = username + "sent_chat_app";
socket.on(event_chat_app, (value) => {
try {
console.log(“value”, value)
} catch (e) {}
});
}
return () => {
socket?.disconnect();
};
}, []);
What can I do to ensure that the syncing issue does not happen again?
The issue was that
client_manager
was missing. I had to add theAsyncRedisManager
to theAsyncServer
. Use a message broker: Implement a message broker like Redis, RabbitMQ, or Kafka to manage the synchronization of messages and events between your multiple workers. When a user sends a message or event, it can be published to the message broker, and all workers can subscribe to it to receive updates.Without it, multiple instances of Socket IO were initiated. In other words,
room1
androom1
could be different for two different users.The code to fix it is below:
I needed to use
pip3 install aioredis
as well to make this work.