fix: make WS handler synchronous — async handler breaks socket.on('message') in @fastify/websocket v8

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ai
2026-05-22 13:31:21 +03:00
parent 71b961ac2b
commit 21edd7f7a3

View File

@@ -52,7 +52,7 @@ async function sendPushToOfflineUsers(userIds: string[], payload: object) {
}
export function setupWebSocket(app: FastifyInstance) {
(app as any).get('/ws', { websocket: true }, async (socket: any, req: any) => {
(app as any).get('/ws', { websocket: true }, (socket: any, req: any) => {
let userId: string | null = null;
try {
@@ -64,21 +64,20 @@ export function setupWebSocket(app: FastifyInstance) {
return;
}
const uid = userId;
// Register connection
if (!connections.has(userId)) connections.set(userId, new Set());
connections.get(userId)!.add(socket);
if (!connections.has(uid)) connections.set(uid, new Set());
connections.get(uid)!.add(socket);
// Update last_seen
await pool.query('UPDATE users SET last_seen = NOW() WHERE id = $1', [userId]);
// Notify others that user is online
const { rows: memberChats } = await pool.query(
'SELECT DISTINCT chat_id FROM chat_members WHERE user_id = $1', [userId]
);
for (const row of memberChats) {
const ids = await getChatMemberIds(row.chat_id);
broadcast(ids.filter(id => id !== userId), { type: 'user_online', payload: { userId, online: true } });
}
// Update last_seen + notify online (fire-and-forget)
pool.query('UPDATE users SET last_seen = NOW() WHERE id = $1', [uid]).catch(() => {});
pool.query('SELECT DISTINCT chat_id FROM chat_members WHERE user_id = $1', [uid]).then(async ({ rows: memberChats }) => {
for (const row of memberChats) {
const ids = await getChatMemberIds(row.chat_id);
broadcast(ids.filter(id => id !== uid), { type: 'user_online', payload: { userId: uid, online: true } });
}
}).catch(() => {});
socket.on('message', async (raw: any, isBinary: boolean) => {
try {
@@ -199,20 +198,19 @@ export function setupWebSocket(app: FastifyInstance) {
});
socket.on('close', async () => {
if (!userId) return;
const set = connections.get(userId);
const set = connections.get(uid);
if (set) {
set.delete(socket);
if (set.size === 0) {
connections.delete(userId);
await pool.query('UPDATE users SET last_seen = NOW() WHERE id = $1', [userId]);
connections.delete(uid);
await pool.query('UPDATE users SET last_seen = NOW() WHERE id = $1', [uid]);
const { rows: memberChats } = await pool.query(
'SELECT DISTINCT chat_id FROM chat_members WHERE user_id = $1', [userId]
'SELECT DISTINCT chat_id FROM chat_members WHERE user_id = $1', [uid]
);
for (const row of memberChats) {
const ids = await getChatMemberIds(row.chat_id);
broadcast(ids, { type: 'user_online', payload: { userId, online: false } });
broadcast(ids, { type: 'user_online', payload: { userId: uid, online: false } });
}
}
}