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:
| Concepto | Descripción | Ejemplo |
|---|---|---|
| Comando | Solicitud para hacer algo | CreateOrder |
| Evento | Notificación de algo que ya pasó | OrderCreated |
| Query | Solicitud de información | GetOrderStatus |
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):
- El evento
OrderCreatedqueda en la cola esperando - Cuando el servicio de inventario vuelve, consume los eventos pendientes
- 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:
StockUpdated { productId: "ABC", quantity: 100 }(timestamp: 10:00:01)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:
| Estrategia | Pros | Contras |
|---|---|---|
| Ordenar por timestamp | Simple | Relojes no sincronizados entre servicios |
| Número de secuencia | Orden garantizado | Requiere coordinación entre publishers |
| Partición por key | Orden dentro de la partición | Limita el paralelismo |
| Versión optimista | No requiere orden global | Requiere 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
productIdcomo 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:
- Los eventos principales (camino feliz)
- Los eventos de compensación (camino infeliz)
- Qué servicio publica y quién consume cada evento
- Cómo manejas los fallos en cada paso
Reflexión
- ¿Cuántos eventos necesitaste para un flujo “simple”?
- ¿Qué tan difícil fue diseñar las compensaciones?
- ¿Preferirías un orquestador central (Saga orquestada) o coreografía?
- ¿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.