Inbox (architectural)
Le journal des évènements consommés — pour qu'un retry du broker ne re-déclenche pas un side effect déjà fait.
Problème
Un broker livre at-least-once : le même message peut être consommé deux fois en cas de redémarrage du consumer entre le traitement et le commit de l'offset. Le side effect métier (ex : facturation) ne doit pas se produire deux fois.
Forces
- Le consumer ne contrôle pas la livraison at-least-once du broker.
- Un side effect non-idempotent (call API externe payant, write fichier comptable) doit être protégé.
- L'inbox doit avoir une clé unique par message_id (UNB control reference, ISA13).
- Le commit broker ne peut pas être dans la même transaction que la DB applicative (sauf XA).
Solution
Créer une table `inbox` (message_id, source, processed_at, status). À la consommation, le consumer (1) tente d'insérer le message_id dans `inbox` ; (2a) si l'insert réussit → exécute le side effect métier dans la même transaction puis COMMIT puis ACK broker ; (2b) si l'insert échoue (unique violation) → message déjà traité, ACK broker sans side effect. Le pattern reproduit la sémantique d'Idempotent Receiver mais au niveau infrastructure.
Implémentation EDI
En EDI, un cas classique : le hub consomme un INVOIC arrivant du partenaire et appelle l'API de comptabilité interne pour créer la facture. Sans Inbox, un retry du broker double la facture. Avec Inbox : la première consommation insère ISA13+sender dans `edi.inbox` + crée la facture en transaction. Le retry voit l'insert échouer, ACK proprement sans re-facturer. Implémentations : pattern manuel sur PostgreSQL, ou bibliothèques Eventuate Tram, MassTransit Inbox.
Anti-patterns
- Inbox sans index unique sur (message_id, source) — le pattern ne marche pas.
- Side effect hors de la transaction d'insert — race condition.
- Inbox sans purge — la table grossit indéfiniment.
- Inbox sur tous les messages indistinctement — overhead inutile pour les flows idempotents par nature.
Patterns liés
- Idempotent Receiver — version code de la même garantie.
- Outbox (architectural) — pattern miroir côté producer.
- Transactional Client — transaction locale.
- Message Store — la table inbox sert souvent de log.
Sources
- Microsoft Learn — Idempotent message processing. learn.microsoft.com/en-us/azure/architecture/reference-architectures/event-hubs/
- Chris Richardson — Microservices Patterns, Inbox Pattern. microservices.io/patterns/data/transactional-outbox.html