Heartbeats: monitorización de tareas programadas
Un heartbeat vigila una tarea programada: un cron, una copia de seguridad nocturna, la limpieza de un worker, la generación de un informe. El principio es el del interruptor de hombre muerto, en lugar de que Quiet Guard pregunte a su tarea si se ha ejecutado, es su tarea la que avisa a Quiet Guard en cada ejecución (un "ping"). Cuando los pings se detienen, usted recibe una alerta.
El problema que resuelve
El seguimiento de excepciones atrapa el código que falla ruidosamente: algo lanza una excepción, usted recibe un informe. Pero las averías más traicioneras son silenciosas:
- la entrada cron se perdió durante una migración de servidor,
- el scheduler está mal configurado (
schedule:runya no se invoca), - la tarea falla tan pronto que ningún manejador de excepciones la ve,
- alguien desactivó el job "temporalmente" hace tres meses.
En todos estos casos nada lanza una excepción, así que nada se reporta. Su copia de seguridad nocturna simplemente deja de existir, y usted lo descubre el día en que la necesita. El heartbeat invierte la lógica: el silencio se convierte en la propia alerta.
Inicio rápido
El cableado recomendado es la macro del scheduler, encadenada directamente a la tarea en routes/console.php:
La macro solo hace ping si la tarea tiene éxito, una tarea que falla permanece silenciosa y por lo tanto dispara la alerta de retraso. También puede hacer ping manualmente desde cualquier código:
o por HTTP (cualquier stack, no solo Laravel):
Registro y armado
- El primer ping registra automáticamente el heartbeat en el proyecto. En ese momento está sin armar: los pings se registran, nada alerta jamás. Es intencionado: primero se conecta el ping, después se decide qué significa "con retraso".
- El armado se hace en el panel de control: abra la pestaña Heartbeats del proyecto, edite el heartbeat y defina su periodo esperado (la frecuencia con la que la tarea debe hacer ping, en minutos) más una tolerancia (retraso adicional aceptado: un scheduler rara vez cae en el segundo exacto).
- Un heartbeat sin periodo esperado sigue siendo un registro pasivo de pings, inofensivo para siempre.
Heartbeats automáticos
El SDK de Laravel, desde su versión 0.4, declara dos heartbeats por sí mismo: scheduler, y uno por cola vigilada (queue-{conexión}-{cola}). Se arman en el primer ping que lleve lo necesario para armarse, con un periodo observado y una tolerancia de periodo más cuatro minutos para el scheduler, nueve minutos (o, desde Laravel 13.10, el --timeout del worker más un minuto) para una cola, ambas topadas en 1440 minutos. La pestaña los marca como Automático y muestra el retraso de la cola: la espera más corta observada, desde el ping anterior, entre que un job de esa cola se crea y un worker lo toma, nunca la espera del propio ping. Ese retraso es una medida, nunca una alerta, y permanece vacío en Laravel 11, y en Laravel 12 antes de la 12.11, cuyo job no lleva marca de creación.
Un heartbeat de cola con retraso alerta por sí mismo, con independencia del scheduler: cuando ambos se detienen, cada uno alerta.
Un heartbeat de cola también puede quedar retrasado sin que nada esté roto, ya que un worker solo hace ping entre dos jobs y solo mientras recorre su bucle: un modo de mantenimiento más largo que la tolerancia (el worker deja de recorrer su bucle, salvo si se ejecuta con --force), un worker en pausa (horizon:pause, o SIGUSR2 enviado a queue:work), un solo job más largo que la tolerancia (incluido un job cuyo propio $timeout supera el --timeout del worker), workers que solo se inician de vez en cuando (queue:work --stop-when-empty desde cron o desde el scheduler) con menos frecuencia que la tolerancia, y queue:listen o queue:work --once, que nunca hacen ping. En esos casos, amplíe aquí la tolerancia de ese heartbeat, que el SDK nunca vuelve a armar, o excluya la cola de MONITOR_QUEUE_HEARTBEATS y elimine la fila.
Para desactivar un heartbeat automático, cambie la variable en la aplicación (vea Heartbeats del SDK) y después elimine la fila aquí. El SDK nunca vuelve a armar una fila existente: si usted desarma un heartbeat automático, permanece desarmado.
Estados
| Estado | Significado |
|---|---|
| Pendiente | Registrado (o rearmado) pero ningún ping evaluado todavía contra el periodo. |
| Sano | El último ping llegó dentro de periodo + tolerancia. |
| Con retraso | Ningún ping dentro de periodo + tolerancia, la alerta ha salido. |
Cada minuto, el servidor comprueba cada heartbeat armado: pasado último ping + periodo + tolerancia, pasa a con retraso y dispara una alerta por avería a través de los canales de notificación del proyecto suscritos al evento heartbeat.overdue (correo electrónico, Slack o webhook, vea Alertas). La protección contra tormentas de alertas se aplica.
La recuperación es silenciosa por diseño: el siguiente ping exitoso devuelve el heartbeat al estado sano, sin notificación. La alerta le dijo que la tarea está bloqueada; el panel de control muestra que ha vuelto a funcionar.
Elegir periodo y tolerancia
- Periodo = la planificación de la tarea. Diaria → 1440. Horaria → 60.
- Tolerancia = el retraso normal para esa tarea. Una copia de seguridad que tarda de 5 a 40 minutos merece una tolerancia generosa (60 por ejemplo); una tarea corta puede quedarse con los 5 por defecto.
- En caso de duda, sea generoso. Un falso "con retraso" a las 3 de la madrugada enseña a ignorar el canal: lo único que una alerta no debe hacer jamás.
Límites y detalles
- Los slugs se normalizan a minúsculas-y-guiones (
nightly-backup); créelos en la interfaz con el mismo alfabeto, o deje que el primer ping los cree. - Un proyecto contiene como máximo 200 heartbeats: una clave de API filtrada no puede inundar la tabla. Los heartbeats automáticos cuentan en ese total.
- Los pings se autentican con la clave de API del proyecto, como cualquier llamada de ingesta (referencia de la API).
- Los heartbeats con retraso aparecen en el Resumen del proyecto (banda de estado) y en la lista Bajo vigilancia del panel, y cuentan como actividad en el resumen semanal.
Está leyendo la documentación Quiet Guard v1.0.