El veredicto de tres estados
Cada componente (una categoría de API o una integración) se clasifica continuamente en uno de tres estados.operational
Todo está dentro de la banda saludable.
degraded
Un cron obsoleto, una única ruta que falla, o una tasa de error de bajo nivel sostenida.
down
Un pico de errores de ventana corta que significa una caída real.
Cómo se computa el veredicto
Funcionalmente: la API cuenta constantemente las solicitudes exitosas y fallidas por componente, observa dos ventanas de tiempo, y elige el peor estado que aplique. Técnicamente, la precedencia se evalúa de arriba hacia abajo:down— tasa de error de ventana corta>= 50%sobre>= 5solicitudes, o (para integraciones) una probe activa fallida.degraded— un cron folded obsoleto, una ruta individual que falla, o una tasa de error de ventana larga sostenida>= 1%sobre>= 5solicitudes.operational— todo lo demás.
La histéresis previene el flapping. Una vez que un componente entra en
degraded, solo
regresa a operational cuando la tasa de error de ventana larga cae por debajo del
umbral de recuperación (0.5%). El último veredicto se cachea en Redis
(health:verdict:{component}).Ventanas de tráfico
Los contadores viven en buckets de Redis de 5 minutos (traffic:{scope}:{ok|err}:{windowStart}, TTL ~70 min). Se leen dos rangos:
Umbrales
Todos los umbrales se exportan desdelib/endpoint/health/integration-traffic.ts,
así que ajustarlos es un cambio de código de una línea revisado en un PR.
Seguimiento por ruta
recordApiTraffic registra tanto un contador de categoría como un contador por ruta. La
ruta se normaliza (normalizeRoutePath) para que los segmentos dinámicos — UUIDs, ids
numéricos, tokens opacos largos — colapsen a [id], lo que acota la cardinalidad. Cada
clave de ruta es {METHOD}:{normalized-path}.
Esto captura una única ruta que falla con fuerza (por ejemplo, una ruta rota de MaihueGO)
dentro de una categoría por lo demás sana: la señal de la ruta degrada toda la
categoría incluso cuando la tasa de error agregada se mantiene baja y de otro modo ocultaría
el problema.
Endpoints de pull por componente
Better Stack no lee Redis ni el estado interno. Consulta un endpoint HTTP por componente:x-health-token, cotejado contra HEALTH_MONITOR_TOKEN:
401cuando el header no coincide.503cuando el token no está configurado (fail closed — nunca expongas la salud sin auth).503solo cuando el veredicto esdown. Tantooperationalcomodegradeddevuelven200; la capa amarilla se publica a través de Status Reports, nunca como downtime. El veredicto completo está siempre en el cuerpo de la respuesta.
Sincronización de degradado (Status Reports)
lib/endpoint/health/degraded-sync.ts reconcilia cada veredicto con los
Status Reports publicados en Better Stack:
- Entrar en
degraded→createDegradedReport, almacenando el id del report enhealth:degraded-report:{component}. - Salir de
degraded→resolveDegradedReportpublica un status updateresolveden el report (nunca lo elimina, de modo que la entrada de la página de estado y su espejo en Slack muestran la recuperación) y limpia el marcador.
BETTERSTACK_STATUS_PAGE_RESOURCES. Se ejecuta desde ambos
crons de salud después de computar los veredictos y es totalmente best-effort (nunca
lanza). Cualquier componente que no esté presente en el mapa simplemente se omite.
Heartbeats de cron
Los heartbeats confirman que el scheduler en sí está vivo — una preocupación separada de la salud de los componentes.pingHeartbeat reintenta una vez con un breve backoff dentro de su timeout, absorbiendo
los baches de red transitorios.
Métricas de infraestructura
El cron de metrics-push (/api/v3/cron/metrics/push) mide la latencia de la base de datos
y de Redis para los gráficos de Infraestructura. Como una única muestra de arranque en frío
producía picos falsos, el colector calienta la conexión con una probe sin cronometrar,
toma tres muestras cronometradas, y reporta la mediana — manteniendo la
cadencia de 5 minutos mientras suaviza los outliers puntuales.
Ruta de la señal de extremo a extremo
Código relacionado
- Motor de veredicto y umbrales:
backend/horizon-api/lib/endpoint/health/ - Cliente de Status Report:
backend/horizon-api/lib/integration/betterstack/status-report.client.ts - Análisis profundo:
docs/initiatives/betterstack/01-architecture.md