Aller au contenu

Heartbeats

Le SDK peut pinger un heartbeat sur le serveur Quiet Guard à chaque exécution de l'une de vos tâches planifiées. Le serveur fonctionne comme un dispositif d'homme mort : une fois le heartbeat armé avec une période attendue, l'absence de pings déclenche une alerte de retard. Une entrée cron perdue, un schedule:run oublié, une tâche désactivée « temporairement » : le silence devient lui-même l'alerte. Le concept complet (statuts, armement, canaux d'alerte) est détaillé dans la documentation du serveur.

La macro du scheduler (recommandée)

Le SDK enregistre une macro monitorHeartbeat() sur les événements planifiés de Laravel. Chaînez-la directement sur la tâche à surveiller, dans routes/console.php :

php
use Illuminate\Support\Facades\Schedule;

Schedule::command('reports:send')->daily()->monitorHeartbeat('reports-send');

Deux propriétés font de la macro le câblage recommandé :

  • Elle ne pingue que si la tâche réussit (elle s'accroche au onSuccess du scheduler). Une tâche qui plante ou sort avec un code non nul n'envoie rien, reste silencieuse et déclenche donc l'alerte de retard. Pinger avant la tâche, ou systématiquement après, ruinerait tout l'intérêt du mécanisme.
  • Elle respecte les garde-fous du SDK au moment de l'exécution : si MONITOR_ENABLED=false, ou si l'environnement courant ne figure pas dans la liste MONITOR_ENVIRONMENTS, le ping est ignoré. Un scheduler de staging exécutant le même code ne pingue donc jamais vos heartbeats de production. Voir Configuration.

Ping manuel

Vous pouvez aussi pinger depuis n'importe quel code avec la commande Artisan, par exemple depuis une ligne cron brute après un script shell :

bash
php artisan monitor:heartbeat reports-send

Si MONITOR_ENABLED=false, la commande affiche un avertissement et n'envoie rien. Elle sort avec un code d'échec quand le ping ne peut pas être délivré (vérifiez MONITOR_URL / MONITOR_KEY).

Battements automatiques

Depuis la version 0.4, le SDK surveille deux choses tout seul, sans une ligne de votre part, en production :

  • Le scheduler. À chaque démarrage de schedule:run (cron compris, et chaque sous-processus que schedule:work lance), il pingue le heartbeat scheduler. Le premier démarrage ne fait qu'enregistrer l'heure ; à partir du second, le ping porte l'écart observé comme période (1 à 1440 minutes) et une tolérance de période plus 4 minutes, plafonnée à 1440 minutes. Avec un cron à la minute, le heartbeat apparaît donc après deux minutes ; avec un cron horaire, après deux heures. Un schedule:run tapé à la main dans un terminal est ignoré, ni enregistré ni pingué, pour qu'un essai manuel n'arme jamais une mauvaise cadence. Plusieurs serveurs qui lancent le même cron sur un cache partagé comptent pour un seul scheduler : un démarrage à moins de 30 secondes de celui qui est enregistré est pris pour ce même démarrage.
  • Vos files. Chaque worker queue:work (Horizon compris) pingue, à chaque tour de sa boucle et même sans job à traiter, un heartbeat queue-{connexion}-{file} par file qu'il consomme et qui est surveillée, au plus une fois par minute et par file. Rien n'est ajouté à la file, aucun job témoin : le ping vient du tour de boucle lui-même. La tolérance est de neuf minutes, ou le --timeout du worker plus une minute quand il est plus long (Laravel 13.10 ou ultérieur ; les versions antérieures gardent neuf minutes), plafonnée à 1440 minutes. Un heartbeat de file en retard alerte de lui-même, indépendamment du scheduler. Le retard de file affiché dans l'onglet Heartbeats est le plus court délai observé, depuis le ping précédent, entre la mise en file d'un job et sa prise par un worker ; une valeur absente veut dire que le worker qui a envoyé le ping n'en a mesuré aucun, alors que d'autres workers de la file ont pu prendre des jobs, et une nouvelle tentative n'est jamais mesurée. Sous Laravel 11, et sous Laravel 12 avant la 12.11, dont le job ne porte pas de date de création, rien n'est mesuré et le retard reste vide.

Ces heartbeats s'arment tout seuls au premier ping qui porte de quoi s'armer : rien n'est créé tant que le scheduler ou un worker n'a pas tourné au moins une fois, et une application sans file ne reçoit jamais d'alerte à ce sujet. La période et la tolérance sont fixées à la création : le SDK ne réarme jamais un heartbeat existant, y compris le sien.

Pour surveiller d'autres files, ou aucune :

dotenv
# Plusieurs files, au format connexion:file
MONITOR_QUEUE_HEARTBEATS=redis:default,redis:emails
# Aucune file
MONITOR_QUEUE_HEARTBEATS=false
# Pas de heartbeat du scheduler
MONITOR_SCHEDULER_HEARTBEAT=false
# Environnements concernés (production par défaut)
MONITOR_HEARTBEAT_ENVIRONMENTS=production

Ces battements passent par votre store de cache par défaut. Celui du scheduler en demande un qui survit au processus (fichier, base de données, Redis) : avec le store array, chaque schedule:run part d'un cache vide, si bien que le heartbeat du scheduler n'est jamais envoyé, un échec silencieux et sans conséquence. Les pings de file partent quand même avec le store array, mais chaque processus worker pingue alors pour son compte au lieu d'un ping par file pour tous les workers. Changer MONITOR_KEY change les clés de cache, si bien que le prochain démarrage recompte comme un premier. Un worker dont un ping échoue n'envoie plus aucun ping de file pendant la minute qui suit : un serveur Quiet Guard injoignable coûte à chaque worker un MONITOR_TIMEOUT par minute, quel que soit le nombre de files. Pour éteindre un heartbeat automatique, changez la variable puis supprimez la ligne dans l'onglet Heartbeats : une ligne existante n'est jamais réarmée par le SDK.

Un heartbeat de file peut passer en retard sans que rien ne soit cassé, parce qu'un worker ne pingue qu'entre deux jobs, et seulement tant qu'il boucle. Les cas connus :

  • un mode maintenance plus long que la tolérance : le worker cesse de boucler jusqu'au retour de l'application, sauf s'il tourne avec --force ;
  • un worker en pause, par php artisan horizon:pause ou un signal SIGUSR2 envoyé à queue:work ;
  • un seul job plus long que la tolérance, y compris un job dont le $timeout propre dépasse le --timeout du worker : la tolérance suit l'option du worker, alors que la valeur du job l'emporte à l'exécution ;
  • des workers lancés seulement de temps en temps, par exemple queue:work --stop-when-empty depuis cron ou depuis le scheduler, moins souvent que la tolérance (neuf minutes par défaut) ;
  • queue:listen et queue:work --once, qui ne bouclent jamais et ne pinguent donc jamais : une file qui passe sur eux après qu'un queue:work a créé son heartbeat tombe en retard.

Dans chacun de ces cas, élargissez la tolérance de ce heartbeat dans l'onglet Heartbeats (le SDK ne réarme jamais une ligne existante, votre valeur reste), ou retirez la file de MONITOR_QUEUE_HEARTBEATS et supprimez sa ligne.

Cycle de vie

  • Le premier ping enregistre automatiquement le heartbeat sur votre projet. Un heartbeat branché avec la macro ou la commande naît non armé : les pings sont enregistrés, rien n'alerte jamais tant que vous n'avez pas défini de période. Les battements automatiques font exception : ils arrivent avec leur période et naissent armés.
  • L'armement se fait dans le tableau de bord : ouvrez l'onglet Heartbeats du projet et définissez la période attendue (plus une tolérance). Le SDK n'arme que ses propres battements automatiques, et seulement à leur création.
  • Le rétablissement est silencieux : après une panne, le ping réussi suivant repasse le heartbeat en sain, sans notification.

Règles de slug

Un slug de heartbeat identifie la tâche : lettres minuscules, chiffres et tirets simples (reports-send, nightly-backup). Le serveur normalise tout le reste ; utilisez donc cet alphabet dès le départ et gardez le slug identique entre la macro et le tableau de bord.

Étape suivante

Poursuivez avec les Sauvegardes chiffrées, le complément naturel : un heartbeat sur votre tâche de sauvegarde vous prévient le jour où elle cesse de tourner.

Vous lisez la documentation Laravel SDK v1.0.