This commit is contained in:
Louis Mazin 2026-02-02 00:21:15 +01:00
parent a6860f364c
commit 40c76d4872
2 changed files with 57 additions and 2 deletions

View File

@ -38,6 +38,7 @@ module.exports = {
{ name: '📡 État Connexion', value: status.wsState || 'N/A', inline: true },
{ name: '🔄 En cours de connexion', value: status.isConnecting ? '⏳ Oui' : '✅ Non', inline: true },
{ name: '💓 Heartbeat Actif', value: status.hasHeartbeat ? '✅ Oui' : '❌ Non', inline: true },
{ name: '⏱️ Timeout Heartbeat', value: status.hasHeartbeatTimeout ? '✅ Oui' : '❌ Non', inline: true },
{ name: '🔍 Vérification Auto', value: status.hasCheckInterval ? '✅ Oui' : '❌ Non', inline: true },
{ name: '⏱️ Reconnexion Planifiée', value: status.hasPendingReconnect ? '⏳ Oui' : '❌ Non', inline: true },
{ name: '🔁 Délai Reconnexion', value: `${Math.round(status.reconnectDelayMs / 1000)}s`, inline: true },
@ -49,6 +50,11 @@ module.exports = {
embed.addFields({ name: '🕐 Dernière Connexion', value: status.connectionTimestamp, inline: false });
}
if (status.lastHeartbeatResponse) {
const timeSinceResponse = status.timeSinceLastResponse ? `${status.timeSinceLastResponse}s` : 'N/A';
embed.addFields({ name: '💓 Dernière Réponse Serveur', value: `${status.lastHeartbeatResponse}\n⏱️ Il y a ${timeSinceResponse}`, inline: false });
}
if (status.monitoringStartTimestamp) {
embed.addFields({ name: '🚀 Démarrage Monitoring', value: status.monitoringStartTimestamp, inline: false });
}
@ -64,6 +70,9 @@ module.exports = {
if (status.hasPendingReconnect) {
recommendations += ` Une reconnexion est prévue dans ${Math.round(status.reconnectDelayMs / 1000)}s.\n`;
}
if (status.timeSinceLastResponse && status.timeSinceLastResponse > 45) {
recommendations += `⚠️ Aucune réponse du serveur depuis ${status.timeSinceLastResponse}s (timeout dans ${60 - status.timeSinceLastResponse}s)\n`;
}
if (recommendations) {
embed.addFields({ name: '💡 Recommandations', value: recommendations, inline: false });

View File

@ -7,6 +7,8 @@ let ws = null;
let reconnectTimeout = null;
let client = null;
let heartbeatInterval = null;
let heartbeatTimeout = null; // Timeout pour détecter si le serveur ne répond plus
let lastHeartbeatResponse = null; // Timestamp de la dernière réponse du serveur
let checkInterval = null;
let refreshCredentialsInterval = null; // Interval pour rafraîchir les credentials périodiquement
let isMonitoring = false;
@ -316,13 +318,43 @@ const connectWebSocket = async (pterodactylToken, serverId) => {
args: [null]
}));
// Configurer le heartbeat
if (heartbeatInterval) clearInterval(heartbeatInterval);
if (heartbeatTimeout) clearTimeout(heartbeatTimeout);
lastHeartbeatResponse = Date.now();
heartbeatInterval = setInterval(() => {
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ event: 'send heartbeat', args: [] }));
try {
ws.send(JSON.stringify({ event: 'send heartbeat', args: [] }));
console.log('💓 [WEBSOCKET] Heartbeat envoyé');
// Configurer un timeout pour détecter si le serveur ne répond plus
if (heartbeatTimeout) clearTimeout(heartbeatTimeout);
heartbeatTimeout = setTimeout(() => {
const timeSinceLastResponse = Date.now() - lastHeartbeatResponse;
if (timeSinceLastResponse > 60000) { // 1 minute sans réponse
console.error('💔 [WEBSOCKET] Timeout: aucune réponse du serveur depuis 1 minute');
console.log('🔄 [WEBSOCKET] Fermeture et reconnexion du WebSocket...');
if (ws) {
ws.close();
}
}
}, 60000);
} catch (error) {
console.error('❌ [WEBSOCKET] Erreur lors de l\'envoi du heartbeat:', error.message);
}
} else {
console.warn('⚠️ [WEBSOCKET] Heartbeat impossible: WebSocket non ouvert (état:', ws ? ws.readyState : 'null', ')');
}
}, 30000);
console.log('💓 [WEBSOCKET] Heartbeat configuré (30s)');
console.log('💓 [WEBSOCKET] Heartbeat configuré (30s avec timeout de 60s)');
}
// Détecter les réponses du serveur (console output, status, etc) pour mettre à jour le lastHeartbeatResponse
if (message.event === 'console output' || message.event === 'status' || message.event === 'stats') {
lastHeartbeatResponse = Date.now();
}
if (message.event === 'console output') {
const log = message.args[0];
@ -430,6 +462,11 @@ const connectWebSocket = async (pterodactylToken, serverId) => {
console.log('💔 [WEBSOCKET] Heartbeat arrêté');
}
if (heartbeatTimeout) {
clearTimeout(heartbeatTimeout);
heartbeatTimeout = null;
}
// Planifier une reconnexion avec backoff (utile lors des redémarrages quotidiens du serveur)
if (isMonitoring) {
scheduleReconnect();
@ -458,6 +495,11 @@ const stopWebSocketOnly = () => {
heartbeatInterval = null;
}
if (heartbeatTimeout) {
clearTimeout(heartbeatTimeout);
heartbeatTimeout = null;
}
if (refreshCredentialsInterval) {
clearInterval(refreshCredentialsInterval);
refreshCredentialsInterval = null;
@ -469,6 +511,7 @@ const stopWebSocketOnly = () => {
}
isConnecting = false;
lastHeartbeatResponse = null;
};
const forceReconnectToRefreshCredentials = async () => {
@ -569,8 +612,11 @@ const getWebSocketStatus = () => {
wsStateRaw: ws ? ws.readyState : null,
connectionTimestamp: connectionTimestamp ? new Date(connectionTimestamp).toISOString() : null,
monitoringStartTimestamp: monitoringStartTimestamp ? new Date(monitoringStartTimestamp).toISOString() : null,
lastHeartbeatResponse: lastHeartbeatResponse ? new Date(lastHeartbeatResponse).toISOString() : null,
timeSinceLastResponse: lastHeartbeatResponse ? Math.round((Date.now() - lastHeartbeatResponse) / 1000) : null,
reconnectDelayMs,
hasHeartbeat: !!heartbeatInterval,
hasHeartbeatTimeout: !!heartbeatTimeout,
hasCheckInterval: !!checkInterval,
hasRefreshInterval: !!refreshCredentialsInterval,
hasPendingReconnect: !!reconnectTimeout