Ir al contenido

Heartbeat (push)

El fallo silencioso que nadie nota: la copia de seguridad nocturna que dejó de ejecutarse tras una actualización, el cron de renovación de certificado que perdió sus permisos, la automatización de Home Assistant que se rompió con un renombrado. Nada se queja, y te enteras el día que necesitas la copia de seguridad.

Un monitor de heartbeat (también llamado dead man’s switch, o un monitor push en Uptime Kuma) invierte la lógica: DumbMonit no contacta nada. El trabajo llama a una URL secreta cada vez que se ejecuta, y es la ausencia de una llamada la que genera la alerta.

Cada monitor heartbeat obtiene una URL de la forma https://<tu DumbMonit>/api/push/<token>. El token es un valor aleatorio de 128 bits, guardado con hash para la búsqueda y cifrado para mostrarlo: se muestra en la página del monitor, con un botón de copiar, durante todo el tiempo que exista el monitor. Es deliberadamente abierto — sin sesión, sin token de API, sin cabecera X-Requested-With — porque una línea curl en un crontab no tiene nada de eso. Tener el token solo te permite decir «el trabajo se ejecutó».

En cada pasada del scheduler (el intervalo del monitor, 60 s por defecto) el recolector lee la hora de la última llamada y escribe:

Situaciónprobe_successEfecto
Ninguna llamada recibida todavía(nada escrito)El monitor muestra Waiting. Sin alerta: el trabajo aún no está en su sitio.
Última llamada dentro del intervalo esperado + gracia1Reporting.
Última llamada más antigua que el intervalo esperado + gracia0, reason="missed"Down; la regla «Heartbeat missed» se activa tras dos minutos.
La última llamada dijo status=down0, reason="reported_down"Down de inmediato, sea lo que sea que diga el reloj.

Una llamada también reevalúa el monitor de inmediato, así que un trabajo que se reanuda limpia su alerta sin esperar a la siguiente pasada del scheduler.

El endpoint responde 204 con un cuerpo vacío cuando la llamada se registra, 404 para un token desconocido o regenerado, 400 para un status que no es ni up ni down, y 429 (con Retry-After) más allá de sesenta llamadas por minuto para un token. Se aceptan tanto GET como POST; HEAD también funciona.

ParámetroSignificado
statusup (por defecto) o down: el trabajo reporta un fallo él mismo.
msgUna palabra libre de explicación, conservada (truncada a 500 caracteres) y mostrada en la página del monitor.

Estos son los parámetros del monitor push de Uptime Kuma: un script escrito para él funciona sin cambios.

Los pasos de abajo son los que muestra el aviso junto al formulario.

  1. En la dirección, escribe una etiqueta corta para el trabajo («nightly-backup», «certbot-renew»): nada se contacta, la etiqueta solo tiene que ser única entre tus heartbeats.

  2. Define el intervalo esperado según la programación del trabajo («24h» para un trabajo nocturno, «1h» para uno por hora) y, si la programación se desvía, un período de gracia más amplio. Guarda el monitor.

  3. La página del monitor muestra la URL a llamar. Añádela al final del trabajo, para que solo se llame cuando el trabajo tuvo éxito:

    curl -fsS -m 10 --retry 3 https://monit.example.com/api/push/<token>
  4. Un trabajo que puede saber cuándo falló puede decirlo en lugar de quedarse en silencio: añade ?status=down&msg=… a la URL, y la alerta se activa de inmediato.

  5. Hasta que llega la primera llamada el monitor muestra «Waiting» y nada se alerta. ¿URL perdida o filtrada? «Regenerate» en la página del monitor emite una nueva; la antigua deja de responder de inmediato.

Credenciales: ninguna.

Una línea de crontab, cada noche a las 03:00, que solo avisa cuando la copia de seguridad tuvo éxito:

0 3 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 --retry 3 https://monit.example.com/api/push/<token> > /dev/null

Un script que reporta su propio fallo, con el código de salida como mensaje:

#!/bin/sh
URL="https://monit.example.com/api/push/<token>"
if /usr/local/bin/backup.sh; then
curl -fsS -m 10 --retry 3 "$URL" > /dev/null
else
curl -fsS -m 10 --retry 3 "$URL?status=down&msg=backup+exit+$?" > /dev/null
fi

Home Assistant, un rest_command llamado al final de una automatización:

rest_command:
dumbmonit_heartbeat:
url: "https://monit.example.com/api/push/<token>"
method: post

Windows Task Scheduler (PowerShell):

Ventana de terminal
Invoke-WebRequest -UseBasicParsing -TimeoutSec 10 "https://monit.example.com/api/push/<token>" | Out-Null
ClaveEtiquetaPor defectoAyuda
expected_intervalExpected interval24hCon qué frecuencia se supone que el trabajo llama: 30m, 1h, 6h, 24h, 7d (o un número de segundos). Una llamada perdida se declara una vez transcurridos ese intervalo más el período de gracia.
graceGrace period10%Tiempo extra tolerado tras el intervalo esperado antes de que el heartbeat cuente como perdido: un porcentaje del intervalo (10%) o una duración fija (15m). Nunca menos de un minuto.

Las duraciones aceptan sufijos s, m, h, d, w y se pueden combinar (1h30m); un número solo es un número de segundos. El intervalo esperado debe estar entre 10 segundos y un año.

Todas etiquetadas probe="push" además de target, host y tag_*, todas con el prefijo dumbmonit_.

MétricaSignificado
probe_success1 si la última llamada llegó a tiempo y no reportó un fallo, 0 en caso contrario. Ausente hasta la primera llamada.
probe_failure_infoPresencia (1) con una etiqueta reason: missed o reported_down.
push_last_seen_secondsAntigüedad de la última llamada.
push_received_totalLlamadas recibidas desde que se creó el token (contador).

Disponibilidad a lo largo de treinta días, como para cualquier monitor de servicio: avg_over_time(dumbmonit_probe_success{probe="push"}[30d]).

Regla integrada que se aplica: Heartbeat missed (advisory, 2 minutos). Las reglas «Service down» y «Service flapping» omiten los heartbeats, y «Monitor unreachable» nunca se activa para ellos: el recolector siempre se ejecuta, solo cambia su veredicto.

RutaSesiónPropósito
GET o POST /api/push/<token>ningunaLa propia llamada. 204, 404, 400 o 429.
GET /api/targets/<id>/pushrequeridaEl monitor: token, path, last_seen_at, last_seen_age_secs, last_status, last_message, received_total, expected_interval_secs, grace_secs, verdict (waiting, on_time, missed, reported_down), settings_error. Se crea en la primera lectura si falta.
POST /api/targets/<id>/push/regenerateadminToken nuevo; la URL anterior responde 404 a partir de entonces. El contador y la última llamada se conservan.