4.4 KiB
Critical Fix: Asynchronous Message Handling
The Problem
The bot was only receiving ONE message from Kosmi then hanging, even though the WebSocket stayed connected.
Root Cause
We were reading WebSocket responses synchronously during connection setup, but the server sends responses in a different order than we were expecting:
What we were doing:
- Send
ExtendedCurrentUserQuery→ Try to read response immediately - Send
RoomChatQuery→ Try to read response immediately - Send
JoinRoom→ Try to read response immediately (loop 10 times)
What the server actually sends:
completeforcurrent-user(from ExtendedCurrentUserQuery)nextforjoin-room(from JoinRoom)nextforroom-chat-query(from RoomChatQuery)- ... more responses ...
The mismatch:
- We sent
RoomChatQueryand tried to read its response - But we actually read the
completemessage from the previouscurrent-userquery! - This consumed a message that
listenForMessagesshould have handled - The message loop got out of sync and stopped processing new messages
Evidence from Logs
time="2025-11-01T16:36:06-04:00" level=info msg="Chat history response: type=complete id=current-user"
We sent a query with ID room-chat-query but received a response with ID current-user - wrong message!
The Fix
Stop reading responses synchronously during setup. Let the listenForMessages goroutine handle ALL incoming messages.
Changes Made
-
Removed synchronous read after
ExtendedCurrentUserQuery- Before: Send query → Read response
- After: Send query → Continue (let listenForMessages handle it)
-
Removed synchronous read after
RoomChatQuery- Before: Send query → Read response
- After: Send query → Continue (let listenForMessages handle it)
-
Removed synchronous loop after
JoinRoom- Before: Send mutation → Loop 10 times reading responses
- After: Send mutation → Brief sleep → Continue (let listenForMessages handle it)
-
Enhanced
listenForMessagesto handle all message types- Added switch statement for
messageTypeNext,messageTypeError,messageTypeComplete - Added specific handling for known operation IDs (
current-user,room-chat-query,join-room,subscribe-messages) - Added better logging for debugging
- Added switch statement for
New Message Flow
Connection Setup (synchronous):
├─ Send connection_init
├─ Wait for connection_ack (ONLY synchronous read)
├─ Send ExtendedCurrentUserQuery
├─ Send JoinRoom
├─ Send RoomChatQuery
├─ Send RoomDisconnect subscription
├─ Send MemberJoins subscription
├─ Send MemberLeaves subscription
├─ Send NewMessageSubscription
└─ Start listenForMessages goroutine
listenForMessages (asynchronous):
├─ Reads ALL incoming messages
├─ Handles responses for all queries/mutations/subscriptions
└─ Processes new chat messages
Expected Behavior After Fix
- ✅ Bot connects and authenticates
- ✅ Bot sends all setup queries/subscriptions
- ✅
listenForMessageshandles all responses in order - ✅ Bot receives ALL messages continuously (not just one)
- ✅ No "ALREADY_CONNECTED" errors
- ✅ WebSocket stays alive and processes messages
Testing
go build
docker-compose build
docker-compose up -d
docker-compose logs -f matterbridge
Look for:
🎧 [KOSMI WEBSOCKET] Message listener started📨 [KOSMI WEBSOCKET] Received: type=next id=current-user✅ Received current user data📨 [KOSMI WEBSOCKET] Received: type=next id=join-room✅ Successfully joined room📨 [KOSMI WEBSOCKET] Received: type=next id=room-chat-query✅ Received chat history- Multiple
📨 [KOSMI WEBSOCKET] Received: type=next id=subscribe-messages - Multiple
Received message from Kosmi:entries
Why This Matters
GraphQL-WS is an asynchronous protocol. The server can send responses in any order, and multiple responses can be in flight at once. By trying to read responses synchronously, we were:
- Breaking the message order - Reading messages meant for the listener
- Creating race conditions - Setup code and listener competing for messages
- Blocking the connection - Waiting for specific responses that might never come (or come in different order)
The fix ensures that only one goroutine (listenForMessages) reads from the WebSocket, eliminating all race conditions and ensuring messages are processed in the order they arrive.