En un monòlit amb una sola base de dades, mantenir la coherència és senzill: ho emboliques tot en una transacció ACID i, si alguna cosa falla, fas ROLLBACK i és com si no hagués passat res. Però en una arquitectura de microserveis cada servei té la seva pròpia base de dades, i una operació de negoci (com "tramitar una comanda") abasta diversos d'ells. No existeix un ROLLBACK global que abasti bases de dades diferents i serveis remots. Com garantim, doncs, la coherència d'una operació que toca comandes, pagaments, inventari i enviaments?

La resposta és el patró Saga: dividim la transacció distribuïda en una seqüència de transaccions locals, cadascuna en un servei, coordinades mitjançant esdeveniments o missatges. Si un pas falla, en lloc d'un rollback executem transaccions de compensació que desfan semànticament els passos anteriors. En aquesta lliçó estudiarem les dues formes d'implementar sagues (coreografia i orquestració), el concepte de compensació i un exemple complet de comanda.

Contingut

  1. El problema de les transaccions distribuïdes
  2. Què és una Saga i les transaccions de compensació
  3. Saga per coreografia
  4. Saga per orquestració
  5. Comparativa coreografia vs orquestració
  6. Exemple complet: tramitar una comanda (amb diagrama)
  7. Errors comuns i consells
  8. Exercicis i solucions
  9. Conclusió

  1. El problema de les transaccions distribuïdes

Imagina el flux "tramitar comanda":

  1. Comandes crea la comanda.
  2. Pagaments cobra al client.
  3. Inventari reserva l'estoc.
  4. Enviaments programa el repartiment.

Si el pas 3 falla (no hi ha estoc), el cobrament del pas 2 ja s'ha realitzat. No podem fer un ROLLBACK distribuït perquè:

  • Cada servei té la seva pròpia BD; no comparteixen transacció.
  • Les solucions clàssiques com el Two-Phase Commit (2PC) bloquegen recursos, escalen malament i creen un fort acoblament. A la pràctica gairebé ningú no les fa servir en microserveis.

La saga accepta una veritat incòmoda: en sistemes distribuïts busquem consistència eventual, no consistència immediata. Hi haurà un instant en què el cobrament està fet però l'estoc no reservat; la saga garanteix que el sistema acabi en un estat coherent (tot confirmat o tot compensat).

  1. Què és una Saga i les transaccions de compensació

Una saga és una seqüència de transaccions locals T1, T2, ..., Tn. Cada Ti té una transacció de compensació Ci que desfà el seu efecte. Si T1, T2, T3 tenen èxit però T4 falla, la saga executa C3, C2, C1 en ordre invers.

Aspectes crucials de les compensacions:

  • No és un rollback tècnic, sinó semàntic. No "esborres" el cobrament; emets un reemborsament. L'historial queda (important per a l'auditoria).
  • Han de ser idempotents i no poder fallar (o tenir reintents robustos), perquè si la compensació falla, el sistema queda inconsistent.
  • Algunes accions no es poden compensar (enviar un email ja enviat). Per a aquestes, es reordena la saga per executar-les al final, quan ja no hi ha marxa enrere (pivot transaction).
Transacció (Ti) Compensació (Ci)
Cobrar al client Reemborsar al client
Reservar estoc Alliberar la reserva
Crear comanda Cancel·lar comanda

  1. Saga per coreografia

En la coreografia no hi ha coordinador central. Cada servei escolta esdeveniments, fa la seva feina i emet un nou esdeveniment que dispara el següent. El flux "emergeix" de les reaccions encadenades (és la topologia de broker de la lliçó 05-01).

flowchart LR
    P[Comandes] -->|ComandaCreada| Pay[Pagaments]
    Pay -->|PagamentConfirmat| Inv[Inventari]
    Inv -->|StockReservat| Env[Enviaments]
    Inv -.->|StockAgotat| Pay
    Pay -.->|PagamentReemborsat| P
  • Camí feliç (línies contínues): cada esdeveniment dispara el servei següent.
  • Camí de fallada (línies puntejades): si Inventari emet StockAgotat, Pagaments reacciona reemborsant i Comandes cancel·la. Les compensacions també viatgen com a esdeveniments.

Avantatges: màxim desacoblament, sense punt únic de fallada. Inconvenients: el flux global no és enlloc; amb molts passos es torna difícil de seguir i depurar (risc de "dependències cícliques" d'esdeveniments).

  1. Saga per orquestració

En l'orquestració, un component central —l'orquestrador— dirigeix la saga: envia comandes a cada servei, espera la resposta i decideix el pas següent o llança les compensacions (és la topologia de mediador).

// Orquestrador de la saga "Tramitar Comanda"
@Component
public class OrquestadorTramitarPedido {

    public void tramitar(String pedidoId) {
        var saga = new EstadoSaga(pedidoId);
        try {
            // Cada pas és una transacció local en un altre servei
            saga.marcar("PEDIDO_CREADO",   pedidos.crear(pedidoId));
            saga.marcar("PAGO_HECHO",      pagos.cobrar(pedidoId));
            saga.marcar("STOCK_RESERVADO", inventario.reservar(pedidoId));
            saga.marcar("ENVIO_PROGRAMADO",envios.programar(pedidoId));
            saga.completar();
        } catch (PasoSagaException ex) {
            // Si alguna cosa falla, compensem en ordre INVERS
            compensar(saga);
        }
    }

    private void compensar(EstadoSaga saga) {
        if (saga.hizo("STOCK_RESERVADO")) inventario.liberar(saga.pedidoId());
        if (saga.hizo("PAGO_HECHO"))      pagos.reembolsar(saga.pedidoId());
        if (saga.hizo("PEDIDO_CREADO"))   pedidos.cancelar(saga.pedidoId());
    }
}

Explicació detallada:

  • L'orquestrador coneix tot el flux: l'ordre dels passos i les seves compensacions. Això centralitza la lògica del procés en un únic lloc llegible.
  • EstadoSaga registra quins passos s'han completat. És essencial persistir-lo (en BD), perquè si l'orquestrador es reinicia a mitges ha de saber per on anava per reprendre o compensar.
  • A compensar, només desfem els passos que que es van executar, en ordre invers: primer alliberar estoc, després reemborsar, després cancel·lar la comanda.
  • En producció, les crides solen ser asíncrones (comandes per cua i respostes per esdeveniments) en lloc d'invocacions bloquejants, però la lògica de coordinació és la mateixa.

  1. Comparativa coreografia vs orquestració

Criteri Coreografia Orquestració
Coordinació Distribuïda (esdeveniments) Centralitzada (orquestrador)
Acoblament Mínim Mitjà (tothom depèn de l'orquestrador)
Visibilitat del flux Baixa (repartit) Alta (en un lloc)
Facilitat de depuració Difícil Fàcil
Punt únic de fallada No Sí (l'orquestrador)
Risc Dependències cícliques d'esdeveniments Orquestrador "déu" sobrecarregat
Ideal per a Pocs passos (2-4), desacoblament màxim Fluxos llargs i complexos

Regla pràctica: fes servir coreografia per a sagues curtes i simples; fes servir orquestració quan el procés tingui molts passos, lògica condicional o necessitis visibilitat i control clars.

  1. Exemple complet: tramitar una comanda (amb diagrama)

Diagrama de seqüència de la saga orquestrada, incloent el camí de compensació quan falta estoc:

sequenceDiagram
    participant O as Orquestrador
    participant P as Comandes
    participant Pay as Pagaments
    participant I as Inventari
    O->>P: crear(comanda)
    P-->>O: ComandaCreada
    O->>Pay: cobrar(comanda)
    Pay-->>O: PagamentConfirmat
    O->>I: reservar(estoc)
    I-->>O: StockAgotat (FALLADA)
    Note over O: Inicia compensació en ordre invers
    O->>Pay: reemborsar(comanda)
    Pay-->>O: PagamentReemborsat
    O->>P: cancel·lar(comanda)
    P-->>O: ComandaCancel·lada

Observa que no hi ha reserva d'estoc per alliberar (aquest pas va fallar), per la qual cosa la compensació arrenca directament en el reemborsament del pagament i acaba cancel·lant la comanda. El sistema queda en un estat coherent: el client no ha pagat i no té comanda.

Un detall clau d'implementació: cada compensació ha de ser idempotent. Si l'orquestrador reintenta reemborsar(comanda) perquè no va rebre resposta, el servei de Pagaments ha de fer servir la clau d'idempotència (lliçó 05-02) per no reemborsar dues vegades.

Errors Comuns i Consells

  • Compensacions que poden fallar i no es reintenten. Si una compensació falla i no hi ha reintents, el sistema queda inconsistent sense remei. Fes-les idempotents i amb reintents persistents.
  • No persistir l'estat de la saga. Si l'orquestrador es reinicia i no sap quins passos va fer, no pot compensar correctament. L'estat de la saga ha de sobreviure a caigudes.
  • Intentar compensar accions irreversibles. Un email enviat no es "des-envia". Col·loca aquestes accions al final de la saga (després de la pivot transaction) o emet una acció correctora (un email de disculpa).
  • Confondre saga amb 2PC. La saga no ofereix aïllament: durant la seva execució, altres poden veure estats intermedis. Cal dissenyar comptant amb això (estats "PENDENT", reserves temporals, etc.).
  • Consell: modela explícitament cada estat intermedi de la comanda (PENDENT_PAGAMENT, PAGAT, CANCEL·LAT) perquè la inconsistència temporal sigui visible i controlada, no accidental.

Exercicis

  1. Defineix les transaccions de compensació per a aquesta saga de reserva de viatge: T1 reservar vol, T2 reservar hotel, T3 llogar cotxe. Si T3 falla, quines compensacions s'executen i en quin ordre?
  2. Per al flux "alta de pòlissa d'assegurança" (validar dades, tarificar, cobrar prima, emetre pòlissa, enviar email de benvinguda) decideix si faries servir coreografia o orquestració i on col·locaries l'enviament de l'email. Justifica-ho.
  3. Explica per què les transaccions de compensació han de ser idempotents, fent servir com a exemple un reemborsament de pagament en una saga amb reintents.

Solucions

  1. Compensacions: C1 cancel·lar vol, C2 cancel·lar hotel, C3 cancel·lar cotxe. Si T3 falla, no hi ha cotxe per cancel·lar; es compensen els passos previs en ordre invers: primer C2 (cancel·lar hotel) i després C1 (cancel·lar vol).
  2. Orquestració, perquè és un flux llarg amb diversos passos i lògica condicional (la tarificació i el cobrament poden rebutjar), i es necessita visibilitat/control per a un procés regulat. L'email de benvinguda va al final, com a acció no compensable després de la pivot transaction (emetre pòlissa): només s'envia quan ja no hi ha marxa enrere, evitant haver de "des-enviar" un correu si alguna cosa falla abans.
  3. Amb reintents (at-least-once), l'orquestrador pot invocar reemborsar(comanda) més d'una vegada si no rep confirmació. Si la compensació no fos idempotent, reemborsaríem al client dues o més vegades. Fent servir la clau d'idempotència del pagament, el servei detecta que aquest reemborsament ja es va fer i l'ignora, garantint un únic reemborsament malgrat els reintents.

Conclusió

El patró Saga resol el problema de les transaccions distribuïdes descomponent-les en transaccions locals coordinades, amb compensacions semàntiques que desfan la feina quan un pas falla. Vam distingir la coreografia (esdeveniments encadenats, màxim desacoblament) de l'orquestració (coordinador central, màxima visibilitat), i vam veure que la idempotència de les compensacions és innegociable. A més, vam assumir que guanyem coherència eventual a canvi de tolerar estats intermedis.

En la lliçó següent, "Streaming de Dades en Temps Real", tanquem el mòdul veient com processar fluxos continus d'esdeveniments —ja no operacions individuals— per a analítica i reacció en temps real amb eines com Kafka Streams.

Curs d'Arquitectura d'Aplicacions

Mòdul 1: Fonaments de l'Arquitectura d'Aplicacions

Mòdul 2: Principis i Tàctiques de Disseny

Mòdul 3: Estils i Patrons Arquitectònics

Mòdul 4: Arquitectures Distribuïdes i Microserveis

Mòdul 5: Arquitectures Dirigides per Esdeveniments i Missatgeria

Mòdul 6: Disseny Dirigit pel Domini (DDD)

Mòdul 7: Dades i Persistència

Mòdul 8: Arquitectura al Núvol i Desplegament

Mòdul 9: Qualitat, Seguretat i Observabilitat

Mòdul 10: Evolució, Governança i Casos Pràctics

© Copyright 2026. Tots els drets reservats