ediverse Explorer la plateforme

À la une PEPPOL BIS Billing 3.0 L’obligation européenne d’e-invoicing arrive : France sept 2026, Belgique janv 2026, Allemagne 2025.

Compensating Action (sous-pattern Saga)

L'opération qui annule sémantiquement une étape déjà commitée — le pattern qui rend possible le rollback distribué quand un XA est impossible. Pierre angulaire des Sagas (Garcia-Molina & Salem, 1987).

Problème

Dans une saga EDI longue (PO → ASN → INVOIC → REMADV), l'étape 5 peut échouer 3 jours après l'étape 1. Aucun système distribué ne permet un rollback transactionnel ACID sur 3 jours et 5 systèmes hétérogènes. Pourtant, il faut bien annuler proprement le travail déjà commit : le stock réservé doit être libéré, le paiement collecté doit être remboursé, la facture envoyée doit être contestée par une note de crédit.

Forces

  • Les transactions distribuées ACID classiques (XA) ne passent pas à l'échelle et bloquent les ressources pendant des heures.
  • Le commit local d'une étape est souvent irréversible techniquement (un INVOIC envoyé est reçu).
  • L'annulation sémantique reste possible : on peut émettre une nouvelle action qui compense l'effet de la première.
  • Toutes les actions ne sont pas équivalentes en réversibilité : certaines (envoi d'email) irréversibles, d'autres (réservation de stock) facilement compensables.
  • Les compensations doivent elles-mêmes être idempotentes : en cas d'échec partiel d'une compensation, la retenter ne doit pas amplifier le dégât.

Solution

Pour chaque étape positive de la saga, définir explicitement l'action de compensation correspondante. Le saga orchestrator (ou la chorégraphie) tient la liste des étapes exécutées et, en cas d'échec, exécute les compensations dans l'ordre inverse. Les compensations sont elles-mêmes des étapes distribuées qui peuvent échouer et doivent être retentées idempotemment. Les actions « non compensables » (paiement irréversible, expédition partie) doivent être minimisées ou placées en fin de saga : au pire, elles tombent dans un workflow d'exception manuel.

Saga avec compensations :

   Étapes positives                Compensations (en cas d'échec)
   ───────────────────             ─────────────────────────────────
   1. CreateOrder         ─────→   1bis. CancelOrder
   2. ReserveStock        ─────→   2bis. ReleaseStock
   3. ChargePayment       ─────→   3bis. RefundPayment
   4. ShipOrder           ─────→   4bis. RecallShipment (parfois impossible)
   5. SendINVOIC          ─────→   5bis. SendCreditNote

   Si étape 3 échoue :
   - exécuter 2bis (ReleaseStock)
   - exécuter 1bis (CancelOrder)
   - notifier le client

   Si étape 4 échoue (très rare car expédition après paiement) :
   - exécuter 4bis si possible
   - sinon → workflow d'exception manuel

   Note : les compensations ne sont PAS l'inverse exact des étapes
   (pas de "Ctrl-Z"). Elles produisent un nouvel effet sémantiquement
   équivalent à l'annulation (ex : CancelOrder = nouveau record en
   DB, pas suppression).

Implémentation EDI

Cas concret : saga PO → ORDRSP → DESADV → INVOIC → REMADV. Étape 4 (DESADV envoyé) puis erreur côté partenaire : le partenaire répond avec un APERAK refus catégorique. La saga déclenche les compensations : étape 4bis = CancelDespatch (envoyer un DESADV de cancellation), étape 3bis = ReleaseShipment en interne (annuler la préparation en entrepôt), étape 2bis = CancelInternalOrder (mettre la commande en état Cancelled). L'étape 1 (ORDERS reçu du partenaire) n'a pas de compensation obligatoire : c'est l'événement initial. Chaque compensation est codée comme une activity Temporal ou comme un Lambda dans Step Functions, idempotente grâce à un Compensation Key. Outils EDI : Camunda 8 modélise nativement les compensations (BPMN compensation boundary event), Temporal les écrit comme activities explicites. Pour un workflow d'1 mois entre PO et REMADV, la liste des compensations possibles est typiquement enregistrée dans un saga state document.

Anti-patterns

  • Compensation oubliée : une étape sans compensation correspondante crée un point de rupture saga.
  • Compensation non idempotente : si elle échoue, la retenter cause une double compensation (double crédit remboursé).
  • Compensation qui appelle l'étape positive symétrique : CancelOrder qui appelle DeleteOrder = perte d'audit. Toujours opérer en append-only.
  • Ordre des compensations bafoué : libérer le stock avant d'annuler la commande peut créer un état incohérent transitoire.
  • Pas de gestion d'échec de compensation : si la compensation échoue, il faut un escalation flow vers l'humain — pas la peine d'essayer une compensation de compensation.
  • Compensation d'action non compensable : certaines actions (paiement irréversible) ne peuvent pas être compensées automatiquement — workflow d'exception explicite à prévoir.

Patterns liés

Sources

  • Garcia-Molina H., Salem K.Sagas, ACM SIGMOD 1987. L'article fondateur qui formalise les Long Lived Transactions et leurs compensations. cornell.edu — Sagas (1987)
  • Richardson C.Microservices Patterns, Manning 2018. Chapitre 4 sur les Sagas, leurs orchestrations et chorégraphies, leurs compensations.
  • Hohpe G., Woolf B.Enterprise Integration Patterns, Addison-Wesley 2003. Process Manager §312 (compensation transactions).
  • OMG BPMN 2.0 Specification. Compensation Boundary Event est un construct natif BPMN pour modéliser visuellement les compensations. omg.org — BPMN 2.0
  • Microsoft Cloud Design Patterns — Compensating Transaction. La fiche pattern Azure. learn.microsoft.com — compensating-transaction
  • Newman S.Building Microservices, O'Reilly 2015 (2e éd. 2021). Chapitre sur les transactions distribuées et leurs alternatives.