Câbler une notification¶
Tout ce qui doit prévenir quelqu'un poste un seul JSON sur le répartiteur. Celui-ci le route vers deux destinations : la messagerie d'équipe et la messagerie mobile. Un émetteur ne connaît ni l'une ni l'autre — c'est le répartiteur qui porte la carte, et c'est ce qui permet d'ajouter ou de retirer une destination sans retoucher un seul émetteur.
flowchart LR
e["Émetteur<br/>script · cron · service · workflow"]
h["Répartiteur<br/>service systemd, 24/7"]
z["Messagerie d'équipe"]
t["Messagerie mobile"]
e -->|"POST JSON"| h
h -->|"synchrone<br/>décide le code de retour"| z
h -.->|"file asynchrone<br/>reprise sur limitation de débit"| t
e -.->|"repli, seulement si le répartiteur ne répond pas"| z
Le geste¶
curl -s -X POST http://<répartiteur>:8099/alerts-notify \
-H 'Content-Type: application/json' \
-d '{"channel":"general","title":"mon titre","message":"mon message"}'
C'est tout. Trois champs, dont un seul est obligatoire en pratique : message.
| Champ | Rôle |
|---|---|
channel |
choisit le fil de destination. Absent ou inconnu → repli sur general, journalisé, et signalé dans la réponse |
title |
devient le sujet du fil côté messagerie d'équipe — voir le piège n°2 |
message |
le corps |
format: "raw" |
force un bloc de code, pour une sortie de commande |
Ce qu'il ne faut pas viser¶
- Pas l'URL publique du moteur de workflows. Elle fonctionne — c'est une façade qui relaie — mais elle ajoute deux composants au chemin d'une alerte. Un nouvel émetteur vise le répartiteur en direct.
- Pas la messagerie d'équipe en direct, sauf pour le repli décrit plus bas. Un émetteur qui la vise directement n'atteint jamais la messagerie mobile, donc jamais un téléphone, donc jamais personne hors du bureau.
- Pas un webhook écrit à la main. Le bloc de repli partagé règle quatre pièges qui ne sont devinables ni l'un ni l'autre, et tous les quatre sont silencieux.
Le repli¶
Le répartiteur rend 200 dès que la messagerie d'équipe a reçu, 502 sinon. Ce 502 est le signal : c'est lui qui déclenche le repli de l'émetteur, en direct vers la messagerie d'équipe.
Le repli existe pour un seul cas : le répartiteur ne répond pas. Il n'atteint pas la messagerie mobile — celle-ci n'est joignable que par le répartiteur.
Deux mécanismes, et le choix ne se discute pas :
| L'émetteur… | Mécanisme |
|---|---|
| tourne depuis le dépôt de notes | import du module partagé |
| est déployé hors dépôt ou vit dans un conteneur | copie du bloc partagé |
La raison du second cas n'est pas le confort : un import depuis un partage réseau
mettrait ce partage sur le chemin d'alerte. Serveur de fichiers absent ⇒ le
script meurt avant sa tentative, et l'on perd aussi le chemin qui aurait marché.
Un repli non testé est un repli dont on suppose qu'il marche
Il ne s'exerce que le jour où le répartiteur tombe — c'est-à-dire le jour où personne ne regarde. Le tester veut dire couper le chemin principal, sur l'hôte concerné, et constater que le message arrive quand même.
Et tester qu'il échoue aussi : vider toutes les sources de clé, pas une seule. Un test négatif qui passe pour une mauvaise raison est pire qu'un test absent.
Inscrire l'émetteur — non négociable¶
Un émetteur qui n'est pas au manifeste n'est jamais mis à niveau quand le bloc partagé évolue. Il continuera de fonctionner, avec la version du jour de sa pose, jusqu'à ce qu'un correctif qu'il n'a pas reçu compte vraiment.
Deux fichiers, dans la même session que la pose :
- le manifeste des copies à tenir à jour ;
- l'inventaire des émetteurs, régénéré par un scan de tous les hôtes.
L'inventaire est la seule vue qui trouve ce que personne n'a déclaré. C'est ainsi qu'ont été découverts quatre exemplaires divergents d'un même watchdog, dont un seul figurait au manifeste.
L'inventaire dit qui mentionne une destination, pas qui émet
Il classe par recherche de motif. Il ne sait pas si le fichier s'exécute. Une mesure de 2026-09 a compté cinq « émetteurs » d'une catégorie dont deux étaient du code mort — leur chemin cible n'existait sur aucune machine. Le faux positif pousse à l'action : « voilà des émetteurs hors du répartiteur, aligne-les ». Aligner du code inerte produit une carte d'apparence complète qui décrit un script qui ne tourne pas.
Avant d'agir sur une ligne de l'inventaire, chercher l'appelant : cron, timer, service, ou un autre script.
Les quatre pièges¶
1. Un code HTTP 200 n'établit pas une remise¶
Plusieurs API encapsulent leurs erreurs dans un corps success: false sous un
200. Un contrôle de la forme curl -o /dev/null -w '%{http_code}' répond alors
à « le serveur web est debout », jamais à « l'appel a marché ». Le bloc partagé lit
le corps et refuse un 200 non-JSON.
C'est ce qui a permis d'établir, en 2026-09, qu'une destination historique était morte depuis trois semaines : elle répondait 200 à tout, avec un code d'erreur « cette API n'existe pas » dans le corps.
2. Le titre est un identifiant de fil¶
Côté messagerie d'équipe, title devient le sujet. Un titre horodaté fabrique un
fil neuf à chaque envoi — 48 fils par jour pour un émetteur qui tourne toutes
les demi-heures.
Le titre porte l'identité de l'émetteur ; ce qui varie va dans message. Un
titre qui varie sur une entité (🔴 CRITICAL — <conteneur>) est légitime : il
donne un fil par conteneur, ce qu'on veut.
3. Une garde sur un jeton mort neutralise le repli¶
Le motif, trouvé sur sept fichiers de quatre hôtes en 2026-09 :
poster_sur_le_repartiteur "$1" && return 0
[ -n "${JETON_D_UNE_DESTINATION_MORTE:-}" ] || return 0 # ← ici
repli_direct "$1"
La garde teste le jeton d'une destination décommissionnée pour autoriser un repli qui, lui, vise une destination bien vivante. Le jeton n'existant plus, la fonction rend 0 sans rien tenter : succès apparent, alerte perdue, précisément le jour où le répartiteur tombe.
Dégât mesuré sur une seule de ces sondes : 18 alertes avalées, dont la panne d'un hôte détectée, décidée, et jamais annoncée.
Ce n'était pas un oubli
Le correctif avait été appliqué à deux fichiers sur six, et jamais propagé. Un correctif qui n'est pas poussé partout où le motif existe est un correctif qu'on croit avoir.
4. Une garde par fenêtre horaire survit à sa raison d'être¶
Certaines sondes portaient HOUR_START / HOUR_END parce que deux machines
dormaient la nuit. Elles ne dorment plus. La garde, elle, est restée — et a
supprimé de vraies alertes en journée de migration.
Gater sur la cause, jamais sur l'heure. Une panne se diagnostique ; elle ne s'explique pas d'avance par le moment où elle survient.
Armer une alerte neuve¶
Une alerte branchée sur un système qui tourne déjà voit d'abord tout le stock.
- Mesurer le volume que la règle produirait, sur une période représentative, avant de brancher la notification.
- Calibrer le seuil sur cet historique — sinon on mesure la cadence de l'instrument, pas l'état du parc.
- Poser une date d'armement : ce qui existait avant n'est pas un événement.
- Poser une hystérésis et une durée de série. Une notification qui se répète à l'identique ne dit rien de plus que la première.
Vérifier¶
# 1. le répartiteur répond
curl -s http://<répartiteur>:8099/health
# 2. le chemin nominal — lire les destinations dans la RÉPONSE, pas le code HTTP
curl -s -X POST http://<répartiteur>:8099/alerts-notify \
-H 'Content-Type: application/json' \
-d '{"channel":"general","title":"probe","message":"test"}'
# 3. le repli — celui qu'on oublie, et le seul qui compte la nuit
/health expose aussi la profondeur de la file de la messagerie mobile. Cette
file existe parce que cette destination impose des limitations de débit : la faire
attendre par la requête entrante coûtait, en 2026-09, 2 295 messages perdus en
quinze jours sur une reprise pourtant correctement écrite, désarmée par une
constante une seconde trop basse.
Ce que la file coûte, et qu'il faut surveiller
Un échec sur cette destination n'est plus visible par l'émetteur : il n'apparaît que dans le journal et dans la profondeur de file. Sans sonde sur cette profondeur, on a remplacé une perte bruyante par une perte muette.
Ce qui ne doit pas passer par le répartiteur¶
- Les sondes hors-bande, qui existent pour parler quand le parc est en panne. Elles doivent atteindre un téléphone sans traverser l'infrastructure surveillée.
- Les ponts conversationnels — permettre de dialoguer avec un assistant depuis une messagerie n'est pas une notification, c'est du transport bidirectionnel.
- Le courrier applicatif destiné à un utilisateur final.
Dernière vérification de cette page : 2026-09-09