1

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?

2
  • > However, the older tabs do not send or receive messages, even though they remain connected to Python Socket.IO and socket.io-client. Do you mean they get a message that they are unauthorized? Are you sure that somewhere on the connect handler it won't delete the old sids connected to this user? Commented Oct 25, 2023 at 6:59
  • Apologies! Just checked, and it seems to be the case that the older tabs CAN send but DO NOT receive messages, even though they remain connected to Python Socket.IO and socket.io-client. Hence, I think that the connect handler is NOT deleting any SIDs. Commented Oct 28, 2023 at 8:11

1 Answer 1

1

The issue was that client_manager was missing. I had to add the AsyncRedisManager to the AsyncServer. 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 and room1 could be different for two different users.

The code to fix it is below:

manager = socketio.AsyncRedisManager("redis://localhost:6379/0")
sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*", client_manager=manager)

I needed to use pip3 install aioredis as well to make this work.

Sign up to request clarification or add additional context in comments.

1 Comment

Nice catch! Very well done.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.