En un monolito con una sola base de datos, mantener la coherencia es sencillo: envuelves todo en una transacción ACID y, si algo falla, haces ROLLBACK y es como si nada hubiera pasado. Pero en una arquitectura de microservicios cada servicio tiene su propia base de datos, y una operación de negocio (como "tramitar un pedido") abarca a varios de ellos. No existe un ROLLBACK global que abarque bases de datos distintas y servicios remotos. ¿Cómo garantizamos entonces la coherencia de una operación que toca pedidos, pagos, inventario y envíos?

La respuesta es el patrón Saga: dividimos la transacción distribuida en una secuencia de transacciones locales, cada una en un servicio, coordinadas mediante eventos o mensajes. Si un paso falla, en lugar de un rollback ejecutamos transacciones de compensación que deshacen semánticamente los pasos anteriores. En esta lección estudiaremos las dos formas de implementar sagas (coreografía y orquestación), el concepto de compensación y un ejemplo completo de pedido.

Contenido

  1. El problema de las transacciones distribuidas
  2. Qué es una Saga y las transacciones de compensación
  3. Saga por coreografía
  4. Saga por orquestación
  5. Comparativa coreografía vs orquestación
  6. Ejemplo completo: tramitar un pedido (con diagrama)
  7. Errores comunes y consejos
  8. Ejercicios y soluciones
  9. Conclusión

  1. El problema de las transacciones distribuidas

Imagina el flujo "tramitar pedido":

  1. Pedidos crea el pedido.
  2. Pagos cobra al cliente.
  3. Inventario reserva el stock.
  4. Envíos programa el reparto.

Si el paso 3 falla (no hay stock), el cobro del paso 2 ya se ha realizado. No podemos hacer un ROLLBACK distribuido porque:

  • Cada servicio tiene su propia BD; no comparten transacción.
  • Las soluciones clásicas como el Two-Phase Commit (2PC) bloquean recursos, escalan mal y crean un fuerte acoplamiento. En la práctica casi nadie las usa en microservicios.

La saga acepta una verdad incómoda: en sistemas distribuidos buscamos consistencia eventual, no consistencia inmediata. Habrá un instante en que el cobro está hecho pero el stock no reservado; la saga garantiza que el sistema acabe en un estado coherente (todo confirmado o todo compensado).

  1. Qué es una Saga y las transacciones de compensación

Una saga es una secuencia de transacciones locales T1, T2, ..., Tn. Cada Ti tiene una transacción de compensación Ci que deshace su efecto. Si T1, T2, T3 tienen éxito pero T4 falla, la saga ejecuta C3, C2, C1 en orden inverso.

Aspectos cruciales de las compensaciones:

  • No es un rollback técnico, sino semántico. No "borras" el cobro; emites un reembolso. El historial queda (importante para auditoría).
  • Deben ser idempotentes y no poder fallar (o tener reintentos robustos), porque si la compensación falla, el sistema queda inconsistente.
  • Algunas acciones no se pueden compensar (enviar un email ya enviado). Para esas, se reordena la saga para ejecutarlas al final, cuando ya no hay vuelta atrás (pivot transaction).
Transacción (Ti) Compensación (Ci)
Cobrar al cliente Reembolsar al cliente
Reservar stock Liberar la reserva
Crear pedido Cancelar pedido

  1. Saga por coreografía

En la coreografía no hay coordinador central. Cada servicio escucha eventos, hace su trabajo y emite un nuevo evento que dispara al siguiente. El flujo "emerge" de las reacciones encadenadas (es la topología de broker de la lección 05-01).

flowchart LR
    P[Pedidos] -->|PedidoCreado| Pay[Pagos]
    Pay -->|PagoConfirmado| Inv[Inventario]
    Inv -->|StockReservado| Env[Envíos]
    Inv -.->|StockAgotado| Pay
    Pay -.->|PagoReembolsado| P
  • Camino feliz (líneas continuas): cada evento dispara al siguiente servicio.
  • Camino de fallo (líneas punteadas): si Inventario emite StockAgotado, Pagos reacciona reembolsando y Pedidos cancela. Las compensaciones también viajan como eventos.

Ventajas: máximo desacoplamiento, sin punto único de fallo. Inconvenientes: el flujo global no está en ningún sitio; con muchos pasos se vuelve difícil de seguir y depurar (riesgo de "dependencias cíclicas" de eventos).

  1. Saga por orquestación

En la orquestación, un componente central —el orquestador— dirige la saga: envía comandos a cada servicio, espera la respuesta y decide el siguiente paso o lanza las compensaciones (es la topología de mediador).

// Orquestador de la saga "Tramitar Pedido"
@Component
public class OrquestadorTramitarPedido {

    public void tramitar(String pedidoId) {
        var saga = new EstadoSaga(pedidoId);
        try {
            // Cada paso es una transacción local en otro servicio
            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 algo falla, compensamos en orden INVERSO
            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ón detallada:

  • El orquestador conoce todo el flujo: el orden de los pasos y sus compensaciones. Esto centraliza la lógica del proceso en un único sitio legible.
  • EstadoSaga registra qué pasos se completaron. Es esencial persistirlo (en BD), porque si el orquestador se reinicia a mitad debe saber por dónde iba para reanudar o compensar.
  • En compensar, solo deshacemos los pasos que se ejecutaron, en orden inverso: primero liberar stock, luego reembolsar, luego cancelar el pedido.
  • En producción, las llamadas suelen ser asíncronas (comandos por cola y respuestas por eventos) en lugar de invocaciones bloqueantes, pero la lógica de coordinación es la misma.

  1. Comparativa coreografía vs orquestación

Criterio Coreografía Orquestación
Coordinación Distribuida (eventos) Centralizada (orquestador)
Acoplamiento Mínimo Medio (todos dependen del orquestador)
Visibilidad del flujo Baja (repartido) Alta (en un sitio)
Facilidad de depuración Difícil Fácil
Punto único de fallo No Sí (el orquestador)
Riesgo Dependencias cíclicas de eventos Orquestador "dios" sobrecargado
Ideal para Pocos pasos (2-4), desacople máximo Flujos largos y complejos

Regla práctica: usa coreografía para sagas cortas y simples; usa orquestación cuando el proceso tenga muchos pasos, lógica condicional o necesites visibilidad y control claros.

  1. Ejemplo completo: tramitar un pedido (con diagrama)

Diagrama de secuencia de la saga orquestada, incluyendo el camino de compensación cuando falta stock:

sequenceDiagram
    participant O as Orquestador
    participant P as Pedidos
    participant Pay as Pagos
    participant I as Inventario
    O->>P: crear(pedido)
    P-->>O: PedidoCreado
    O->>Pay: cobrar(pedido)
    Pay-->>O: PagoConfirmado
    O->>I: reservar(stock)
    I-->>O: StockAgotado (FALLO)
    Note over O: Inicia compensación en orden inverso
    O->>Pay: reembolsar(pedido)
    Pay-->>O: PagoReembolsado
    O->>P: cancelar(pedido)
    P-->>O: PedidoCancelado

Observa que no hay reserva de stock que liberar (ese paso falló), por lo que la compensación arranca directamente en el reembolso del pago y termina cancelando el pedido. El sistema queda en un estado coherente: el cliente no ha pagado y no tiene pedido.

Un detalle clave de implementación: cada compensación debe ser idempotente. Si el orquestador reintenta reembolsar(pedido) porque no recibió respuesta, el servicio de Pagos debe usar la clave de idempotencia (lección 05-02) para no reembolsar dos veces.

Errores Comunes y Consejos

  • Compensaciones que pueden fallar y no se reintentan. Si una compensación falla y no hay reintentos, el sistema queda inconsistente sin remedio. Hazlas idempotentes y con reintentos persistentes.
  • No persistir el estado de la saga. Si el orquestador se reinicia y no sabe qué pasos hizo, no puede compensar correctamente. El estado de la saga debe sobrevivir a caídas.
  • Intentar compensar acciones irreversibles. Un email enviado no se "des-envía". Coloca esas acciones al final de la saga (tras la pivot transaction) o emite una acción correctora (un email de disculpa).
  • Confundir saga con 2PC. La saga no ofrece aislamiento: durante su ejecución, otros pueden ver estados intermedios. Hay que diseñar contando con ello (estados "PENDIENTE", reservas temporales, etc.).
  • Consejo: modela explícitamente cada estado intermedio del pedido (PENDIENTE_PAGO, PAGADO, CANCELADO) para que la inconsistencia temporal sea visible y controlada, no accidental.

Ejercicios

  1. Define las transacciones de compensación para esta saga de reserva de viaje: T1 reservar vuelo, T2 reservar hotel, T3 alquilar coche. Si T3 falla, ¿qué compensaciones se ejecutan y en qué orden?
  2. Para el flujo "alta de póliza de seguro" (validar datos, tarificar, cobrar prima, emitir póliza, enviar email de bienvenida) decide si usarías coreografía u orquestación y dónde colocarías el envío del email. Justifica.
  3. Explica por qué las transacciones de compensación deben ser idempotentes, usando como ejemplo un reembolso de pago en una saga con reintentos.

Soluciones

  1. Compensaciones: C1 cancelar vuelo, C2 cancelar hotel, C3 cancelar coche. Si T3 falla, no hay coche que cancelar; se compensan los pasos previos en orden inverso: primero C2 (cancelar hotel) y luego C1 (cancelar vuelo).
  2. Orquestación, porque es un flujo largo con varios pasos y lógica condicional (la tarificación y el cobro pueden rechazar), y se necesita visibilidad/control para un proceso regulado. El email de bienvenida va al final, como acción no compensable tras la pivot transaction (emitir póliza): solo se envía cuando ya no hay marcha atrás, evitando tener que "des-enviar" un correo si algo falla antes.
  3. Con reintentos (at-least-once), el orquestador puede invocar reembolsar(pedido) más de una vez si no recibe confirmación. Si la compensación no fuera idempotente, reembolsaríamos al cliente dos o más veces. Usando la clave de idempotencia del pago, el servicio detecta que ese reembolso ya se hizo y lo ignora, garantizando un único reembolso pese a los reintentos.

Conclusión

El patrón Saga resuelve el problema de las transacciones distribuidas descomponiéndolas en transacciones locales coordinadas, con compensaciones semánticas que deshacen el trabajo cuando un paso falla. Distinguimos la coreografía (eventos encadenados, máximo desacoplamiento) de la orquestación (coordinador central, máxima visibilidad), y vimos que la idempotencia de las compensaciones es innegociable. Asumimos, además, que ganamos coherencia eventual a cambio de tolerar estados intermedios.

En la siguiente lección, "Streaming de Datos en Tiempo Real", cerramos el módulo viendo cómo procesar flujos continuos de eventos —no ya operaciones individuales— para analítica y reacción en tiempo real con herramientas como Kafka Streams.

Curso de Arquitectura de Aplicaciones

Módulo 1: Fundamentos de la Arquitectura de Aplicaciones

Módulo 2: Principios y Tácticas de Diseño

Módulo 3: Estilos y Patrones Arquitectónicos

Módulo 4: Arquitecturas Distribuidas y Microservicios

Módulo 5: Arquitecturas Dirigidas por Eventos y Mensajería

Módulo 6: Diseño Dirigido por el Dominio (DDD)

Módulo 7: Datos y Persistencia

Módulo 8: Arquitectura en la Nube y Despliegue

Módulo 9: Calidad, Seguridad y Observabilidad

Módulo 10: Evolución, Gobernanza y Casos Prácticos

© Copyright 2026. Todos los derechos reservados