ADR-0005 : Boîte d’envoi transactionnelle sur Marten / PostgreSQL
| Statut | Accepté |
| Date | 2025-11 |
| Décideurs | Équipe de développement Edukit |
| Périmètre | Edukit-OrgService, Edukit-VM |
Contexte
Les services Edukit doivent à la fois modifier leur état métier (en base) et publier des messages (sur RabbitMQ) au cours d’une même opération. Exemple : une saga marque une VM comme Running, persiste ce changement, puis publie VmCredentialIssued pour qu’OrgService envoie le courriel à l’étudiant.
Le piège classique est la double écriture : valider la transaction base puis publier le message en deux opérations séparées. Si le processus tombe entre les deux, on obtient soit un état métier sans message (l’étudiant ne reçoit jamais ses identifiants), soit un message sans état métier (un courriel envoyé pour une VM qui n’existe pas). Aucune des deux situations n’est acceptable.
Il faut donc une garantie d’atomicité entre la mutation métier et l’intention de publication, sans recourir à une transaction distribuée (coûteuse et fragile) entre PostgreSQL et RabbitMQ.
Décision
Adopter le patron boîte d’envoi transactionnelle (transactional outbox) implémenté par Marten, sur la même instance PostgreSQL que les données métier.
- L’écriture du message sortant se fait dans la même transaction PostgreSQL que la mutation métier. Un message est donc publié si et seulement si la transaction qui le produit est validée.
- Wolverine relaie ensuite la ligne de boîte d’envoi vers RabbitMQ. Les confirmations RabbitMQ (
PublisherConfirmations) ferment la boucle côté courtier : la ligne n’est effacée qu’après acquittement du courtier. Une boîte de réception durable symétrique est activée côté consommateurs. - Le stockage document de Marten cohabite avec le relationnel EF Core dans la même base, séparé par schéma PostgreSQL :
publicpour le métier relationnel,wolverine_sagaspour les sagas et la boîte d’envoi de VmService,wolverine_orgservicepour la boîte d’envoi d’OrgService.
Conséquences
Bénéfices
- Plus de double écriture : l’état métier et la publication sont atomiques. C’est la garantie qui rend fiable la chaîne de transmission des identifiants jusqu’au courriel étudiant.
- Livraison au moins une fois de bout en bout (outbox plus confirmations courtier). Les gestionnaires sont conçus idempotents en conséquence (voir ADR-0004).
- Pas de nouvelle technologie à administrer : Marten repose sur PostgreSQL, déjà présent. Pas de second moteur de base, JSONB performant pour le stockage document, concurrence optimiste native pour les sagas.
- Administration simplifiée : la séparation par schéma isole logiquement métier et messagerie (sauvegardes, droits, observabilité) sans imposer une instance dédiée.
Coûts et limites
- La boîte d’envoi ajoute une latence de publication (le relai n’est pas instantané) et une charge d’écriture supplémentaire en base. Acceptable au regard du volume d’Edukit.
- Couplage à PostgreSQL : la garantie d’atomicité repose sur le fait que métier et outbox partagent la même base transactionnelle. Changer de base métier impliquerait de revoir ce choix.
- Nécessite une politique de purge / rétention des lignes traitées (gérée par Wolverine / Marten).
Alternatives écartées
- Publication directe après commit (double écriture) : la plus simple, mais c’est précisément le défaut à éviter (perte ou fantôme de message en cas de panne). Écartée.
- EventStoreDB ou MongoDB comme magasin de documents / d’événements : ajouterait une technologie à déployer et à administrer, sans bénéfice par rapport à Marten sur la base PostgreSQL déjà en place.
- Transaction distribuée (2PC) entre PostgreSQL et RabbitMQ : complexe, fragile, mal supportée par RabbitMQ, et contraire à l’objectif de simplicité opérationnelle.
- SQL Server / autre support de boîte d’envoi : aucune raison d’introduire un second SGBD relationnel à côté de PostgreSQL.