Día 28 de 30 Fase 7: API Gateway, API-First, Arquitectura Hexagonal Enterprise y Sagas

Arquitecturas Distribuidas: Sagas, Circuit Breaker, Resiliencia y Librerías Spring Boot

Patrón Saga (Orquestación vs Coreografía), Resilience4j, Spring Boot Actuator y Starters Esenciales

Visión de conjunto. Sales entendiendo cómo funciona y cuándo usarlo; dominarlo pide más práctica en un proyecto real.

  • 4.5h de estudio
  • 5 conceptos
  • 3 preguntas
  • 1 katas
SagasCircuit BreakerResilience4jSpring Boot ActuatorStartersRetry
Al terminar este día sabrás 4
  • Coordinar una operación que abarca varios servicios con una saga y sus compensaciones.
  • Elegir entre coreografía y orquestación según el tamaño del flujo.
  • Proteger las llamadas remotas con circuit breaker, timeout, reintentos y bulkhead.
  • Exponer salud y métricas con Actuator de forma segura.

El Patrón Saga: Transacciones Distribuidas sin 2PC

En un sistema de microservicios, una operación de negocio (e.g. "crear pedido") puede involucrar múltiples servicios (pedidos, inventario, pagos, envíos). Una Saga coordina esta operación como una secuencia de transacciones locales donde cada servicio confirma su parte y publica un evento. Si un paso falla, se ejecutan acciones compensatorias (rollback lógico) en los servicios previos.

En una línea Saga: CrearPedido -> ReservarStock -> ProcesarPago. Si ProcesarPago falla -> LiberarStock -> CancelarPedido.

Pasos y compensaciones de una saga de pedido text
Paso                         Servicio       Acción                         Compensación
1. Crear pedido              pedidos        estado = PENDIENTE             estado = CANCELADO
2. Reservar stock            inventario     reservar(pedido, líneas)       liberar(pedido)
3. Cobrar                    pagos          cobrar(pedido, importe)        reembolsar(pedido)
4. Reservar transporte       envíos         reservar(pedido, dirección)    cancelarReserva(pedido)
5. Confirmar pedido          pedidos        estado = CONFIRMADO            (paso final, no se compensa)

Si falla el paso 4:
  reembolsar(pedido)  ->  liberar(pedido)  ->  pedido CANCELADO
Cada compensación usa el id del pedido como clave de idempotencia.
Cómo funciona por dentro

Cuando una operación de negocio toca varios servicios, cada uno con su propia base de datos, no hay una transacción que los abarque. Una saga la descompone en una secuencia de transacciones locales, una por servicio. Cada paso confirma su parte y desencadena el siguiente. Si un paso falla, se ejecutan transacciones de compensación para deshacer semánticamente los pasos ya confirmados, en orden inverso.

Compensar no es hacer rollback: el cobro ya ocurrió y se ve en el extracto, así que la compensación es un reembolso. Por eso las compensaciones deben ser idempotentes (se pueden reintentar sin efectos dobles) y diseñadas desde el principio, paso a paso.

Las sagas no ofrecen aislamiento: otros procesos pueden ver estados intermedios. Se mitiga con estados explícitos (PENDIENTE_PAGO, RESERVADO) que el resto del sistema entiende, y ordenando los pasos para que los que no se pueden compensar (enviar un correo, emitir una factura legal) vayan al final.

Reemplaza las transacciones distribuidas (2PC/XA) que son frágiles y lentas en sistemas distribuidos, por una coordinación eventual basada en eventos.

Se conecta con CompensaciónConsistencia EventualOrquestación vs Coreografía

Cuatro bloques cronometrados. No pases al siguiente sin tener el resultado esperado.

  1. Bloque 1: Patrón Saga y Transacciones Distribuidas (0 - 25 min)

    Qué estudiar. Saga por coreografía vs orquestación, acciones compensatorias.

    Pregunta a responder. ¿Cómo compensar un pago ya cobrado si el servicio de envíos falla?

    Resultado esperado. Diagrama de una Saga de 4 pasos con compensaciones.

  2. Bloque 2: Circuit Breaker y Resilience4j (25 - 50 min)

    Qué estudiar. Configuración de @CircuitBreaker, estados CLOSED/OPEN/HALF_OPEN, fallbacks.

    Pregunta a responder. ¿Cómo evitar que un servicio caído colapse todo el sistema?

    Resultado esperado. Servicio con Circuit Breaker y fallback funcional.

  3. Bloque 3: Starters de Spring Boot y Actuator (50 - 80 min)

    Qué estudiar. Listado de starters esenciales, endpoints de Actuator, configuración de health probes.

    Pregunta a responder. ¿Qué endpoints de Actuator son seguros de exponer públicamente?

    Resultado esperado. application.yml con Actuator configurado para Kubernetes readiness/liveness.

  4. Cierre y Consolidación (80 - 90 min)

    Qué estudiar. Repaso de patrones de resiliencia y checklist de librerías.

    Pregunta a responder. ¿Qué 5 librerías no pueden faltar en cualquier proyecto Spring Boot de producción?

    Resultado esperado. Notas consolidadas con el stack de librerías recomendado.

Tres formas de comprobar si lo has entendido, de menos a más exigente: explicarlo con tus palabras, responder preguntas trampa y resolver el reto del tutor.

Explícalo desde cero

Lee cada ficha y explícala en voz alta antes de seguir: si puedes contárselo a alguien que empieza, lo has entendido.

Por qué las transacciones distribuidas (2PC/XA) son inadecuadas para microservicios

Lo que debes entender

El protocolo 2PC (Two-Phase Commit) requiere que un coordinador central bloquee recursos en TODAS las bases de datos participantes hasta que todas confirmen. Si una base de datos es lenta o está caída, todas las demás quedan bloqueadas esperando. En un sistema de microservicios con decenas de servicios independientes, esto crea cuellos de botella masivos. Las Sagas reemplazan el bloqueo pesimista por compensaciones optimistas.

Analogía para contarlo

Un 2PC es como una carrera de relevos donde TODOS los corredores deben estar listos antes de que suene la pistola. Una Saga es como corredores independientes que corren y, si uno se cae, los anteriores desandan el camino (compensación).

Lo que suele explicarse mal

Pensar que se necesita una "super-transacción" que abarque todos los microservicios. Las Sagas aceptan la consistencia eventual.

Señal de que aún no lo dominas

Si intentas usar @Transactional de Spring para coordinar operaciones en bases de datos de microservicios distintos.

Preguntas trampa

Responde de memoria, en voz alta o por escrito, y después abre la respuesta razonada: lo importante es el porqué, no la palabra exacta.

Nivel 1 (Básico) ¿Qué es un fallback en un Circuit Breaker y por qué es importante? Ver respuesta

Respuesta razonada

Un fallback es la respuesta alternativa que se devuelve cuando la llamada protegida falla o el circuito está abierto. Puede ser un valor por defecto, datos de una caché (aunque estén algo desactualizados), una respuesta degradada («precio no disponible») o encolar la operación para más tarde.

Es importante porque convierte el fallo de una dependencia en una degradación controlada en lugar de un error en cascada: la página de producto se sigue mostrando sin las recomendaciones, en vez de devolver un 500. Pero un fallback debe ser honesto: nunca puede inventar un resultado que el negocio interprete como real, como dar un pago por bueno cuando no se sabe. En esos casos el fallback correcto es un error claro o un estado «pendiente».

Qué está evaluando la pregunta

Un fallback es la respuesta alternativa que se devuelve cuando el circuito está abierto (servicio caído). Sin fallback, el usuario recibe un error críptico. Con fallback, puede recibir datos cacheados, un mensaje informativo o una respuesta parcial degradada que mantiene la funcionalidad mínima.

Nivel 2 (Intermedio) ¿Cuándo es mejor una Saga por coreografía y cuándo por orquestación? Ver respuesta

Respuesta razonada

Coreografía cuando el flujo es corto (dos o tres pasos), estable y cada servicio puede reaccionar a eventos sin necesitar una visión global. Mantiene el acoplamiento mínimo y no introduce un componente central.

Orquestación cuando hay muchos pasos, lógica condicional, tiempos de espera, compensaciones complejas o necesidad de saber en todo momento en qué estado está cada operación (soporte, auditoría). El flujo queda escrito en un solo lugar, es más fácil de cambiar y de probar, a cambio de un componente más que mantener. En la práctica muchos sistemas combinan ambas: orquestación dentro de un proceso de negocio complejo y eventos coreografiados para notificar al resto de la organización.

Qué está evaluando la pregunta

Coreografía encaja en flujos simples de 2-3 servicios con eventos lineales. Orquestación encaja en flujos complejos de 4+ servicios con ramificaciones, condiciones y compensaciones sofisticadas donde el flujo debe ser visible y depurable desde un solo punto.

Nivel 3 (Entrevista Senior) ¿Cómo implementarías la compensación en una Saga si el servicio de pagos confirma el cobro pero el servicio de envíos falla al reservar el transporte? Ver respuesta

Respuesta razonada

Al fallar la reserva de transporte, el orquestador (o el servicio de envíos con un evento TransporteNoDisponible) inicia las compensaciones en orden inverso: primero Reembolsar(pedido) en pagos, después LiberarStock(pedido) en inventario y por último marcar el pedido como CANCELADO, notificando al cliente. Antes de compensar puede tener sentido reintentar la reserva o probar otro transportista, si el negocio lo permite.

Las compensaciones deben ser idempotentes, usando el id del pedido como clave: si el reembolso se reintenta, la pasarela no debe devolver el dinero dos veces. También deben reintentarse hasta tener éxito, porque una compensación que falla deja el sistema inconsistente; si tras varios intentos sigue fallando, la saga pasa a un estado que requiere intervención manual y genera una alerta.

Qué está evaluando la pregunta

El orquestador de la Saga debe ejecutar la compensación en orden inverso: primero emitir un evento/comando ReembolsarPago al servicio de pagos para devolver el dinero, y luego CancelarPedido al servicio de pedidos. Cada compensación debe ser idempotente porque puede ejecutarse múltiples veces si el sistema de mensajería la reintenta.

Reto del tutor

Un equipo junior implementa un microservicio que llama a un servicio externo de verificación de identidad. Cuando el servicio externo está caído, su aplicación hace Thread.sleep(30000) y reintenta. Explica por qué este enfoque es desastroso y cómo lo rediseñarías con patrones de resiliencia.

Lo que una respuesta suele tener bien

Señala que el sleep bloquea el hilo durante 30 segundos.

Lo que suele quedarse en la superficie

Decir que use un try-catch.

El concepto de fondo que suele faltar

No advertir que cada petición concurrente bloqueará su hilo 30 segundos. Con 200 peticiones simultáneas, los 200 hilos del pool de Tomcat estarán congelados y la aplicación dejará de responder por completo (thread starvation).

Cómo lo respondería alguien senior en una entrevista

Es un antipatrón catastrófico: (1) Thread starvation: 200 peticiones simultáneas congelan 200 hilos de Tomcat durante 30s cada uno, dejando la app muerta; (2) El servicio externo caído recibe una avalancha de reintentos que empeoran su situación. Solución: (a) Circuit Breaker con Resilience4j que detecte el umbral de fallos y deje de enviar peticiones; (b) Retry con backoff exponencial (100ms, 200ms, 400ms) limitado a 3 intentos; (c) Timeout de 3 segundos máximo por petición; (d) Fallback que devuelva una respuesta degradada (verificación pendiente). En Java 21 con Virtual Threads, el bloqueo no agota los hilos del SO, pero sigue siendo ineficiente y saturará el servicio externo.

Proyecto «Pedidos» · paso 28 de 30

Saga del pedido y resiliencia

Coordinar reserva de stock, cobro y envío entre servicios, deshaciendo lo hecho si algo falla.

De qué va el proyecto

El backend de una tienda online: clientes, catálogo de productos y pedidos con sus líneas, pagos y envíos. Empieza como un proyecto Maven con records y termina como un sistema con API REST, seguridad, mensajería, contenedores y observabilidad. Cada paso construye sobre el anterior, así que trabaja siempre en el mismo repositorio.

Qué hacer

  1. Implementa la saga reserva de stock → cobro → envío, con una compensación para cada paso.
  2. Protege la llamada a la pasarela de pago simulada con un circuit breaker de Resilience4j y un fallback.
  3. Expón /actuator/health con los grupos de liveness y readiness.

Está listo cuando

  • Si el cobro falla, el stock reservado vuelve a estar disponible.
  • Con la pasarela caída, el circuit breaker se abre y los pedidos quedan pendientes de pago en lugar de fallar.

Katas: ejercicios cortos

Reglas de oro

  • Nunca uses @Transactional para coordinar operaciones en bases de datos de microservicios distintos; usa el patrón Saga.
  • Configura siempre Circuit Breaker + Retry + Timeout en llamadas a servicios externos.
  • Define un fallback para cada Circuit Breaker que devuelva una respuesta degradada pero funcional.
  • Protege los endpoints de Actuator con seguridad; solo expón health, info y prometheus en producción.
  • Diseña las acciones compensatorias de las Sagas para ser idempotentes.
Se guarda automáticamente

Fuentes oficiales

Revisado el . Este día en Markdown