Nivel 4 · 35 min
Patrón Saga
El patrón Saga gestiona transacciones distribuidas entre microservicios. Como los microservicios tienen bases de datos separadas, las transacciones ACID que abarcan múltiples servicios son imposibles sin 2PC (que es impráctico a escala). Una Saga es una secuencia de transacciones locales, cada una publicando eventos para disparar el siguiente paso, con transacciones compensatorias para el rollback.
Definición de Saga y Motivación
En un monolito, una transacción de negocio (colocar pedido → reservar stock → cobrar pago → enviar) corre en una sola transacción ACID. En microservicios, cada servicio tiene su propia DB — sin transacciones cross-service. 2PC (Two-Phase Commit) funciona pero es un lock distribuido que destruye disponibilidad y crea un cuello de botella del coordinador. Las Sagas reemplazan 2PC: cada paso es una transacción local. Si el paso N falla, los pasos 1..N-1 se compensan (deshacen via operaciones de negocio). La saga se completa cuando todos los pasos tienen éxito o todas las compensaciones se completan.
Coreografía vs Orquestación
Coreografía: cada servicio escucha eventos y publica nuevos eventos cuando su paso se completa. Sin coordinador central — los servicios reaccionan a eventos. Ventajas: desacoplado, resiliente. Desventajas: difícil de trazar el flujo general, lógica distribuida difícil de entender y testear. Orquestación: un Saga Orchestrator central envía comandos a servicios y espera respuestas. Mantiene la máquina de estados de la saga. Ventajas: flujo claro, un solo lugar para manejo de fallos, monitoreo más fácil. Desventajas: punto único de fallo, los servicios conocen al orquestador. Preferí orquestación para sagas complejas ('>'3 pasos), coreografía para flujos reactivos simples.
Transacciones Compensatorias y Manejo de Fallos
Las transacciones compensatorias son deshacer a nivel de negocio — no son ROLLBACKs de base de datos. Cada paso con efectos secundarios debe tener una transacción compensatoria: ReservarInventario → LiberarInventario, CobrarPago → ReembolsarPago. Las compensaciones no son reversiones exactas — una tarjeta de crédito cobrada puede reembolsarse pero el cargo apareció brevemente. La idempotencia es obligatoria — el orquestador puede reintentar tanto pasos hacia adelante como compensaciones. Escenarios de fallo: un paso falla, la compensación tiene éxito → rollback limpio. Una compensación falla → la saga queda atascada. Estrategia: reintentar la compensación con backoff exponencial, alertar ante fallos repetidos, intervención manual para sagas atascadas.
Code example
// Máquina de estados de saga orquestada
enum SagaState { STARTED, STOCK_RESERVED, PAYMENT_CHARGED,
COMPENSATING, FAILED, COMPLETED }
class OrderSaga {
void handle(OrderPlaced event) {
state = STARTED;
inventoryService.send(new ReserveStock(event.getOrderId()));
}
void handle(StockReserved event) {
state = STOCK_RESERVED;
paymentService.send(new ChargePayment(event.getOrderId()));
}
void handle(PaymentFailed event) {
state = COMPENSATING;
inventoryService.send(new ReleaseStock(event.getOrderId()));
}
}