feat: añade auto-ensure con reintentos y backoff en webhook

Co-authored-by: aider (openrouter/openai/gpt-5) <aider@aider.chat>
main
borja 4 months ago
parent ecff2a5643
commit 9883af5d02

@ -244,4 +244,96 @@ export class WebhookManager {
return false; return false;
} }
} }
// ===== Auto-ensure loop con reintentos y backoff =====
private static autoEnsureTimer: any = null;
private static autoEnsureActive: boolean = false;
private static autoEnsureAttempts: number = 0;
private static getRetryConfig() {
const n = (v: any, d: number) => {
const x = Number(v);
return Number.isFinite(x) && x >= 0 ? x : d;
};
const initial = n(process.env.WEBHOOK_RETRY_INITIAL_DELAY_MS, 1000);
const max = Math.max(initial, n(process.env.WEBHOOK_RETRY_MAX_DELAY_MS, 60000));
const degraded = Math.max(max, n(process.env.WEBHOOK_RETRY_DEGRADED_INTERVAL_MS, 300000));
const jitter = String(process.env.WEBHOOK_RETRY_JITTER || 'true').toLowerCase();
return {
initialDelayMs: initial,
maxDelayMs: max,
degradedIntervalMs: degraded,
jitter: ['true', '1', 'yes', 'on'].includes(jitter),
maxAttempts: Number.isFinite(Number(process.env.WEBHOOK_RETRY_MAX_ATTEMPTS))
? Math.max(0, Number(process.env.WEBHOOK_RETRY_MAX_ATTEMPTS))
: Infinity
};
}
private static jitter(val: number, enabled: boolean): number {
if (!enabled) return val;
const factor = 0.5 + Math.random(); // 0.5x - 1.5x
return Math.max(1, Math.floor(val * factor));
}
private static nextDelayMs(attempt: number, cfg: ReturnType<typeof this.getRetryConfig>): number {
// attempt 0 -> initial, 1 -> 2x, etc. capped at max, luego degradado cada degradedIntervalMs
const pow = Math.min(cfg.maxDelayMs, cfg.initialDelayMs * Math.pow(2, attempt));
return this.jitter(pow, cfg.jitter);
}
static startAutoEnsure(): void {
if (this.autoEnsureActive) {
return;
}
this.autoEnsureActive = true;
this.autoEnsureAttempts = 0;
const cfg = this.getRetryConfig();
const attemptOnce = async () => {
// Validación de config: si falta algo, abortar sin reintentos
try {
this.validateConfig();
} catch (e) {
console.error('❌ Webhook auto-ensure aborted due to invalid configuration:', e instanceof Error ? e.message : e);
this.stopAutoEnsure();
return;
}
try {
await this.registerWebhook();
const ok = await this.verifyWebhook();
if (ok) {
console.log('✅ Webhook is active');
this.stopAutoEnsure();
return;
}
throw new Error('verify returned false');
} catch (err) {
if (!this.autoEnsureActive) return; // pudo ser parado durante espera
const a = this.autoEnsureAttempts++;
const delay = a < 10 ? this.nextDelayMs(a, cfg) : cfg.degradedIntervalMs;
const msg = err instanceof Error ? `${err.message}` : String(err);
console.warn(`⚠️ Webhook ensure attempt #${a + 1} failed: ${msg}. Retrying in ${delay}ms`);
this.autoEnsureTimer = setTimeout(() => {
// Evitar múltiples overlapped
if (!this.autoEnsureActive) return;
attemptOnce();
}, delay);
}
};
// Disparar el primer intento sin esperar
attemptOnce();
}
static stopAutoEnsure(): void {
if (this.autoEnsureTimer) {
try { clearTimeout(this.autoEnsureTimer); } catch {}
this.autoEnsureTimer = null;
}
this.autoEnsureActive = false;
}
} }

Loading…
Cancel
Save