Messaging : files, topics, idempotence
Le message est le ciment du distribué (découplage temporel, charge lissée, retry).
Prérequis : cours 4.3 (event-driven).
Pourquoi
Le message est le ciment du distribué (découplage temporel, charge lissée, retry). Mais « au moins une fois » + redémarrages = doublons garantis : sans idempotence, chaque retry est une double-facturation en puissance.
Concepts
- File (queue) : un message → un consommateur (tâches : mails, Miniatures, webhooks). Topic : un message → tous les abonnés (événements :
order.placed→ facturation + stats + notifs). - ACK et visibilité : le message reste « invisible » pendant le traitement ; sans ACK (crash), il réapparaît → doublon normal, pas bug. D'où l'idempotence obligatoire.
- Idempotence en pratique : clé unique métier (
eventId/orderIden contrainte UNIQUE, ou table des traités) : « déjà vu » = ACK sans effet. Opérations naturellement idempotentes (SET status=X) préférées aux incréments. - Poison message : message qui fait toujours crasher → boucle infinie. Parade : compteur de tentatives + dead-letter queue (file des exclus) + alerte.
Exemple : consommateur sûr
async function onOrderPlaced(msg) {
if (await alreadyProcessed(msg.eventId)) return ack(msg); // doublon : sans effet
await doWork(msg); // transaction qui inclut le marquage
ack(msg);
}
Cas réel
Webhooks de paiement retraités après redémarrage : sans clé d'idempotence, 214 clients débités 2 fois un samedi. Remboursements + excuse publique. Depuis : UNIQUE(event_id) partout, tests qui envoient chaque message 3 fois.
Pièges
- ACK avant traitement (« pour aller vite ») : crash = message perdu à jamais. Toujours après.
- Ordre supposé dans une file multi-consommateurs : pas garanti — partitionner par clé métier si l'ordre compte.
- Retry infini sans DLQ : un poison bloque/ralentit toute la file. Compteur + DLQ + alerte.
À retenir
File = un consommateur, topic = tous ; doublons normaux → idempotence ; poison → DLQ.
Pas de correction en ligneConfrontez votre code aux résultats attendus du cours.