</>
Plan du cours — 56/64

Le patron Outbox : fiabiliser les événements

Avancé

Problème : après avoir enregistré une commande, il faut publier un événement (Kafka, RabbitMQ). Si l'application plante entre les deux, la commande existe sans événement (ou l'inverse). Il n'existe pas de transaction commune entre la base et le broker.

La solution : écrire l'événement dans la même transaction#

BEGIN;
INSERT INTO commandes (client_id, total) VALUES (42, 99.90) RETURNING id;
INSERT INTO outbox (type, cle, charge_utile)
VALUES ('commande.creee', '1234', '{"id": 1234, "total": 99.90}');
COMMIT;

Un processus séparé lit régulièrement la table outbox, publie les messages au broker, puis les marque comme publiés :

SELECT id, type, cle, charge_utile
FROM   outbox
WHERE  publie_le IS NULL
ORDER  BY id
LIMIT  100
FOR UPDATE SKIP LOCKED;          -- plusieurs relais possibles, sans double traitement

Propriétés et limites#

  • Au moins une fois : le relais peut publier un message puis planter avant de le marquer ; les consommateurs doivent donc être idempotents (voir ci-dessous).
  • L'ordre est conservé par clé si l'on publie dans l'ordre d'id par clé.
  • Alternative : capturer les changements du journal WAL avec la réplication logique (Debezium) : plus complexe, mais sans table outbox interrogée.

Cas pratique : le patron outbox est la réponse standard à la question d'entretien « comment garantir qu'on n'enregistre pas une commande sans publier l'événement (ni l'inverse) sans transaction distribuée ? ».