Simulador de Eventos

Diseña y traza flujos de eventos entre microservicios — desde la publicación hasta el consumo y las reacciones en cadena.

Objetivo

En este laboratorio vas a diseñar flujos de eventos entre microservicios, trazar su recorrido completo y anticipar los problemas que pueden surgir en una arquitectura event-driven.

Los eventos son el sistema nervioso de una arquitectura distribuida. Entender cómo fluyen es fundamental para diseñar sistemas desacoplados y resilientes.

Conceptos previos

Antes de empezar, asegúrate de entender la diferencia entre:

ConceptoDescripciónEjemplo
ComandoSolicitud para hacer algoCreateOrder
EventoNotificación de algo que ya pasóOrderCreated
QuerySolicitud de informaciónGetOrderStatus

Los eventos son hechos inmutables — algo que ya ocurrió y no se puede deshacer. Los comandos son intenciones — pueden ser rechazados.


Ejercicio 1: Diseñar un flujo de eventos

Escenario

Un usuario compra un producto en tu e-commerce. Diseña el flujo completo de eventos desde que hace clic en “Comprar” hasta que recibe la confirmación.

Servicios involucrados

  • Servicio de Órdenes: crea y gestiona órdenes
  • Servicio de Inventario: reserva y descuenta stock
  • Servicio de Pagos: procesa el cobro
  • Servicio de Notificaciones: envía emails y push
  • Servicio de Analytics: registra métricas de negocio

Tu tarea

Completa el diagrama de eventos:

Usuario hace clic en "Comprar"


[Servicio de Órdenes]
    │ publica: OrderCreated { orderId, userId, items, total }

    ├──► [Servicio de Inventario]
    │       consume: OrderCreated
    │       acción: reservar stock
    │       publica: _______________

    ├──► [Servicio de Pagos]
    │       consume: _______________
    │       acción: procesar cobro
    │       publica: _______________

    ├──► [Servicio de Notificaciones]
    │       consume: _______________
    │       acción: _______________

    └──► [Servicio de Analytics]
            consume: _______________
            acción: _______________

Solución

Ver flujo completo
Usuario hace clic en "Comprar"


[Servicio de Órdenes]
    │ publica: OrderCreated { orderId, userId, items, total }

    ├──► [Servicio de Inventario]
    │       consume: OrderCreated
    │       acción: reservar stock para los items
    │       publica: StockReserved { orderId, items }
    │              o StockInsufficient { orderId, items }

    ├──► [Servicio de Pagos]
    │       consume: StockReserved
    │       acción: procesar cobro con el proveedor
    │       publica: PaymentCompleted { orderId, transactionId }
    │              o PaymentFailed { orderId, reason }

    ├──► [Servicio de Notificaciones]
    │       consume: PaymentCompleted
    │       acción: enviar email de confirmación al usuario
    │       consume: PaymentFailed
    │       acción: enviar email de fallo al usuario

    └──► [Servicio de Analytics]
            consume: OrderCreated, StockReserved, PaymentCompleted
            acción: registrar métricas de conversión y revenue

Ejercicio 2: Manejar el camino infeliz

Escenario

¿Qué pasa cuando algo falla en medio del flujo? Diseña las compensaciones.

Caso 1: El stock se reservó pero el pago falló

OrderCreated → StockReserved → PaymentFailed


                              ¿Qué pasa ahora?

Tu tarea: ¿Qué evento debe publicar el servicio de pagos? ¿Quién lo consume? ¿Qué acción toma?

Ver solución
PaymentFailed { orderId, reason }

    ├──► [Servicio de Inventario]
    │       consume: PaymentFailed
    │       acción: liberar stock reservado
    │       publica: StockReleased { orderId, items }

    ├──► [Servicio de Órdenes]
    │       consume: PaymentFailed
    │       acción: marcar orden como fallida
    │       publica: OrderCancelled { orderId, reason }

    └──► [Servicio de Notificaciones]
            consume: OrderCancelled
            acción: notificar al usuario que el pago falló

Este es el patrón Saga con coreografía: cada servicio reacciona a los eventos y ejecuta compensaciones cuando algo falla. No hay un orquestador central.

Caso 2: El servicio de inventario está caído

OrderCreated → [Inventario: CAÍDO] → ???

Tu tarea: ¿Qué pasa con el evento OrderCreated? ¿Se pierde? ¿Se reintenta?

Ver solución

Si usas un message broker con colas durables (RabbitMQ, Kafka):

  1. El evento OrderCreated queda en la cola esperando
  2. Cuando el servicio de inventario vuelve, consume los eventos pendientes
  3. El procesamiento continúa normalmente (con delay)

Clave: La cola actúa como buffer temporal. El evento no se pierde mientras la cola sea durable y los mensajes persistentes.

Consideración: Si el servicio está caído mucho tiempo, la cola crece. Necesitas:

  • Alertas por tamaño de cola
  • TTL en mensajes para evitar procesar eventos muy viejos
  • Lógica de compensación si el evento ya no es relevante

Ejercicio 3: Ordenamiento de eventos

El problema

Dos eventos llegan al servicio de inventario:

  1. StockUpdated { productId: "ABC", quantity: 100 } (timestamp: 10:00:01)
  2. StockUpdated { productId: "ABC", quantity: 50 } (timestamp: 10:00:00)

El evento 2 se publicó primero pero llegó después. Si procesas en orden de llegada, el stock queda en 50 (incorrecto — debería ser 100).

Tu tarea

¿Cómo garantizas el orden correcto? Evalúa estas estrategias:

EstrategiaProsContras
Ordenar por timestampSimpleRelojes no sincronizados entre servicios
Número de secuenciaOrden garantizadoRequiere coordinación entre publishers
Partición por keyOrden dentro de la particiónLimita el paralelismo
Versión optimistaNo requiere orden globalRequiere lógica de resolución de conflictos
Ver recomendación

La estrategia más práctica para la mayoría de los casos es partición por key:

  • En Kafka: usar productId como partition key
  • Todos los eventos del mismo producto van a la misma partición
  • Dentro de una partición, el orden está garantizado
  • Diferentes productos se procesan en paralelo

Para casos donde necesitas orden global, usa un número de secuencia generado por el publisher y rechaza eventos con secuencia menor a la última procesada.


Ejercicio 4: Diseña tu propio flujo

Tu tarea

Elige uno de estos escenarios y diseña el flujo completo de eventos:

Opción A: Sistema de reservas de hotel

  • Servicios: Reservas, Habitaciones, Pagos, Notificaciones
  • Flujo: usuario reserva → verificar disponibilidad → cobrar → confirmar

Opción B: Plataforma de delivery

  • Servicios: Pedidos, Restaurantes, Riders, Tracking, Notificaciones
  • Flujo: usuario pide → restaurante acepta → rider asignado → entrega

Opción C: Sistema de suscripciones

  • Servicios: Usuarios, Suscripciones, Pagos, Acceso, Notificaciones
  • Flujo: usuario se suscribe → cobro recurrente → renovación/cancelación

Para cada uno, define:

  1. Los eventos principales (camino feliz)
  2. Los eventos de compensación (camino infeliz)
  3. Qué servicio publica y quién consume cada evento
  4. Cómo manejas los fallos en cada paso

Reflexión

  1. ¿Cuántos eventos necesitaste para un flujo “simple”?
  2. ¿Qué tan difícil fue diseñar las compensaciones?
  3. ¿Preferirías un orquestador central (Saga orquestada) o coreografía?
  4. ¿Cómo debuggearías un problema en un flujo de 5+ eventos?

Los sistemas event-driven son poderosos pero complejos. La clave es diseñar los flujos antes de escribir código — y siempre pensar en qué pasa cuando algo falla.