fix(socket): improve connection stability with heartbeat and auto-reconnect
- Backend: Add pingInterval (25s) and pingTimeout (60s) for better keep-alive - Frontend: Increase reconnection attempts to Infinity (keep trying forever) - Frontend: Add reconnect event handlers to rejoin rooms after reconnection - Frontend: Check initial connection state when reusing socket instance
This commit is contained in:
@@ -21,6 +21,12 @@ function initializeSocket(httpServer) {
|
|||||||
origin: process.env.CORS_ORIGIN || 'http://localhost:8080',
|
origin: process.env.CORS_ORIGIN || 'http://localhost:8080',
|
||||||
credentials: true,
|
credentials: true,
|
||||||
},
|
},
|
||||||
|
// Ping/pong heartbeat configuration
|
||||||
|
pingInterval: 25000, // Send ping every 25 seconds
|
||||||
|
pingTimeout: 60000, // Wait 60 seconds for pong before considering disconnected
|
||||||
|
// Allow upgrade from polling to websocket
|
||||||
|
transports: ['polling', 'websocket'],
|
||||||
|
allowUpgrades: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Authentication middleware for Socket.IO
|
// Authentication middleware for Socket.IO
|
||||||
|
|||||||
@@ -46,15 +46,37 @@ const useEventChat = (slug, userId, event, messagesContainerRef) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Socket event listeners
|
// Function to join room (used on connect and reconnect)
|
||||||
socket.on('connect', () => {
|
const joinRoom = () => {
|
||||||
setIsConnected(true);
|
setIsConnected(true);
|
||||||
// Join event room
|
|
||||||
socket.emit('join_event_room', { slug });
|
socket.emit('join_event_room', { slug });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if already connected (socket instance may already be connected)
|
||||||
|
if (socket.connected) {
|
||||||
|
joinRoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Socket event listeners
|
||||||
|
socket.on('connect', joinRoom);
|
||||||
|
|
||||||
|
socket.on('disconnect', (reason) => {
|
||||||
|
setIsConnected(false);
|
||||||
|
console.log('🔌 Disconnected:', reason);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('disconnect', () => {
|
// Handle reconnection - rejoin room automatically
|
||||||
setIsConnected(false);
|
socket.on('reconnect', (attemptNumber) => {
|
||||||
|
console.log('🔄 Reconnected after', attemptNumber, 'attempts');
|
||||||
|
// Room will be joined via 'connect' event
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('reconnect_attempt', (attemptNumber) => {
|
||||||
|
console.log('🔄 Reconnection attempt', attemptNumber);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('reconnect_error', (error) => {
|
||||||
|
console.error('🔄 Reconnection error:', error);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Receive message history (initial 20 messages)
|
// Receive message history (initial 20 messages)
|
||||||
@@ -92,8 +114,11 @@ const useEventChat = (slug, userId, event, messagesContainerRef) => {
|
|||||||
// Cleanup
|
// Cleanup
|
||||||
return () => {
|
return () => {
|
||||||
socket.emit('leave_event_room');
|
socket.emit('leave_event_room');
|
||||||
socket.off('connect');
|
socket.off('connect', joinRoom);
|
||||||
socket.off('disconnect');
|
socket.off('disconnect');
|
||||||
|
socket.off('reconnect');
|
||||||
|
socket.off('reconnect_attempt');
|
||||||
|
socket.off('reconnect_error');
|
||||||
socket.off('message_history');
|
socket.off('message_history');
|
||||||
socket.off('event_message');
|
socket.off('event_message');
|
||||||
socket.off('active_users');
|
socket.off('active_users');
|
||||||
|
|||||||
@@ -64,8 +64,18 @@ const useMatchChat = (match, userId, slug) => {
|
|||||||
// Socket event listeners
|
// Socket event listeners
|
||||||
socket.on('connect', joinMatchRoom);
|
socket.on('connect', joinMatchRoom);
|
||||||
|
|
||||||
socket.on('disconnect', () => {
|
socket.on('disconnect', (reason) => {
|
||||||
setIsConnected(false);
|
setIsConnected(false);
|
||||||
|
console.log('🔌 Match chat disconnected:', reason);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle reconnection
|
||||||
|
socket.on('reconnect', (attemptNumber) => {
|
||||||
|
console.log('🔄 Match chat reconnected after', attemptNumber, 'attempts');
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('reconnect_attempt', (attemptNumber) => {
|
||||||
|
console.log('🔄 Match chat reconnection attempt', attemptNumber);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Receive messages
|
// Receive messages
|
||||||
@@ -82,6 +92,8 @@ const useMatchChat = (match, userId, slug) => {
|
|||||||
return () => {
|
return () => {
|
||||||
socket.off('connect', joinMatchRoom);
|
socket.off('connect', joinMatchRoom);
|
||||||
socket.off('disconnect');
|
socket.off('disconnect');
|
||||||
|
socket.off('reconnect');
|
||||||
|
socket.off('reconnect_attempt');
|
||||||
socket.off('match_message');
|
socket.off('match_message');
|
||||||
};
|
};
|
||||||
}, [match, userId]);
|
}, [match, userId]);
|
||||||
|
|||||||
@@ -26,9 +26,17 @@ export function connectSocket() {
|
|||||||
auth: {
|
auth: {
|
||||||
token,
|
token,
|
||||||
},
|
},
|
||||||
|
// Reconnection settings
|
||||||
reconnection: true,
|
reconnection: true,
|
||||||
reconnectionAttempts: 5,
|
reconnectionAttempts: Infinity, // Keep trying forever
|
||||||
reconnectionDelay: 1000,
|
reconnectionDelay: 1000, // Start with 1 second delay
|
||||||
|
reconnectionDelayMax: 5000, // Max 5 seconds between attempts
|
||||||
|
randomizationFactor: 0.5, // Add some randomness to prevent thundering herd
|
||||||
|
// Timeout settings
|
||||||
|
timeout: 20000, // 20 seconds connection timeout
|
||||||
|
// Transport settings - prefer websocket but start with polling for reliability
|
||||||
|
transports: ['polling', 'websocket'],
|
||||||
|
upgrade: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('connect', () => {
|
socket.on('connect', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user