feat: añadir health check para reiniciar instancia de Evolution API

Co-authored-by: aider (openrouter/z-ai/glm-4.6) <aider@aider.chat>
main
brobert 1 month ago
parent 80c38a6590
commit f2ee3bbd11

@ -4,6 +4,8 @@ import { toIsoSqlUTC } from '../utils/datetime';
export class MaintenanceService {
private static _timer: any = null;
private static _healthCheckTimer: any = null;
private static _lastRestartAttempt: number = 0;
private static get retentionDays(): number {
const v = Number(process.env.GROUP_MEMBERS_INACTIVE_RETENTION_DAYS);
@ -11,19 +13,44 @@ export class MaintenanceService {
return 180; // por defecto 180 días
}
private static get evolutionApiConfig() {
return {
url: process.env.EVOLUTION_API_URL,
instance: process.env.EVOLUTION_API_INSTANCE,
apiKey: process.env.EVOLUTION_API_KEY,
intervalMs: Number(process.env.HEALTH_CHECK_INTERVAL_MS || '120000'), // 2 min por defecto
restartCooldownMs: Number(process.env.HEALTH_CHECK_RESTART_COOLDOWN_MS || '900000'), // 15 min por defecto
};
}
static start(): void {
if (process.env.NODE_ENV === 'test' && process.env.FORCE_SCHEDULERS !== 'true') return;
if (this.retentionDays <= 0) return;
const intervalMs = 24 * 60 * 60 * 1000; // diario
this._timer = setInterval(() => {
this.cleanupInactiveMembersOnce().catch(err => {
console.error('❌ Error en cleanup de miembros inactivos:', err);
});
this.reconcileAliasUsersOnce().catch(err => {
console.error('❌ Error en reconcile de alias de usuarios:', err);
});
}, intervalMs);
// --- Tareas diarias existentes ---
if (this.retentionDays > 0) {
const intervalMs = 24 * 60 * 60 * 1000; // diario
this._timer = setInterval(() => {
this.cleanupInactiveMembersOnce().catch(err => {
console.error('❌ Error en cleanup de miembros inactivos:', err);
});
this.reconcileAliasUsersOnce().catch(err => {
console.error('❌ Error en reconcile de alias de usuarios:', err);
});
}, intervalMs);
}
// --- Nuevo Health Check de Evolution API ---
const { url, instance, apiKey, intervalMs } = this.evolutionApiConfig;
if (url && instance && apiKey) {
console.log('[MaintenanceService] Iniciando health check de Evolution API...');
this._healthCheckTimer = setInterval(() => {
this.performEvolutionHealthCheck().catch(err => {
console.error('❌ Error en el health check de Evolution API:', err);
});
}, intervalMs);
} else {
console.warn('[MaintenanceService] Variables de entorno para el health check de Evolution API (URL, INSTANCE, API_KEY) no encontradas. Health check desactivado.');
}
}
static stop(): void {
@ -31,6 +58,10 @@ export class MaintenanceService {
clearInterval(this._timer);
this._timer = null;
}
if (this._healthCheckTimer) {
clearInterval(this._healthCheckTimer);
this._healthCheckTimer = null;
}
}
static async cleanupInactiveMembersOnce(instance: Database = db, retentionDays: number = this.retentionDays): Promise<number> {
@ -98,4 +129,51 @@ export class MaintenanceService {
return 0;
}
}
/**
* Verifica el estado de la instancia de Evolution API y la reinicia si es necesario.
*/
private static async performEvolutionHealthCheck(): Promise<void> {
const { url, instance, apiKey, restartCooldownMs } = this.evolutionApiConfig;
const stateUrl = `${url}/instance/connectionState/${instance}`;
const restartUrl = `${url}/instance/restart/${instance}`;
const headers = { apikey: apiKey };
try {
const response = await fetch(stateUrl, { method: 'GET', headers });
if (!response.ok) {
console.error(`[HealthCheck] Error al consultar estado de Evolution API: ${response.status} ${response.statusText}`);
return;
}
const data = await response.json();
const currentState = data?.instance?.state;
console.log(`[HealthCheck] Estado de la instancia '${instance}': ${currentState}`);
if (currentState !== 'open') {
const now = Date.now();
if (now - this._lastRestartAttempt > restartCooldownMs) {
console.warn(`[HealthCheck] La instancia no está 'open'. Estado actual: ${currentState}. Intentando reiniciar...`);
try {
const restartResponse = await fetch(restartUrl, { method: 'PUT', headers });
if (restartResponse.ok) {
console.log(`[HealthCheck] Petición de reinicio para '${instance}' enviada exitosamente.`);
this._lastRestartAttempt = now;
} else {
console.error(`[HealthCheck] Fallo al reiniciar la instancia. Status: ${restartResponse.status} ${restartResponse.statusText}`);
}
} catch (restartError) {
console.error('[HealthCheck] Error de red al intentar reiniciar la instancia:', restartError);
}
} else {
console.log(`[HealthCheck] La instancia no está 'open', pero esperando cooldown de ${Math.round(restartCooldownMs / 60000)} minutos para no sobrecargar la API.`);
}
}
} catch (error) {
console.error('[HealthCheck] Error de red o inesperado al verificar el estado de la Evolution API:', error);
}
}
}

Loading…
Cancel
Save