Descubre cómo lograr el orden por agregado en sistemas distribuidos y la evolución natural hacia el uso de sagas. Artículo reescrito desde milanjovanovic.tech.

Cómo garantizar el orden de mensajes en sistemas distribuidos: de eventos a sagas

Cómo garantizar el orden de mensajes en sistemas distribuidos: de eventos a sagas

En la mayoría de arquitecturas distribuidas, el reto no es mantener un orden global de mensajes, sino asegurar que los eventos relacionados a una misma entidad —como un OrderId o CustomerId— sean procesados secuencialmente. Este principio es clave para preservar la consistencia y evitar errores sutiles en flujos de negocio complejos.

El atractivo inicial de los eventos de dominio

Los eventos de dominio ofrecen una solución elegante: cada vez que un agregado cambia de estado, emite un evento que desencadena acciones en otros componentes. Por ejemplo, un pedido puede generar eventos como OrderPlaced, PaymentCaptured y OrderShipped. Sin embargo, este mecanismo presenta fragilidades cuando se utiliza para integraciones, ya que pueden surgir problemas de duplicidad, reintentos y desorden si la publicación de eventos falla o se produce fuera de la transacción.

Patrón Outbox: fiabilidad, pero no orden

El patrón Outbox refuerza la fiabilidad al almacenar los eventos pendientes en la misma transacción que la actualización del agregado. Un proceso aparte se encarga de publicar estos eventos a la cola de mensajes, asegurando que nada se pierda ni se publique duplicado. No obstante, aunque mejora la robustez, no garantiza el orden de procesamiento una vez que los mensajes entran en la cola.

El problema de los consumidores concurrentes

Para escalar, es habitual aumentar el número de consumidores de una cola (competing consumers). Pero esta técnica puede romper el orden esperado: dos consumidores distintos podrían procesar eventos del mismo agregado en paralelo y fuera de secuencia. Esto genera inconsistencias, especialmente bajo carga o en presencia de reintentos automáticos.

La verdadera necesidad: orden por agregado

Lo ideal es mantener hilos de procesamiento independientes y ordenados por cada agregado. Los agregados ya delimitan las fronteras de consistencia y los eventos suelen generarse secuencialmente. Si se asegurara que sólo un consumidor procese eventos por cada clave agregada, el problema prácticamente desaparece.

¿Una solución simple? Un único consumidor

Implementar un solo consumidor garantiza el orden, pero limita la escalabilidad y la capacidad de procesamiento. En sistemas de alto volumen, esto puede ser un cuello de botella.

Procesamiento encadenado: el paso hacia las sagas

Una estrategia más sofisticada es que, tras procesar un evento de un agregado, el sistema publique explícitamente el siguiente evento a procesar. Así, se asegura que sólo un mensaje por agregado está activo, manteniendo el orden y permitiendo escalar horizontalmente en diferentes agregados. Este patrón lleva naturalmente a la saga coreografiada: un flujo de trabajo donde cada etapa desencadena la siguiente mediante eventos.

Saga coreografiada vs. saga orquestada

La saga coreografiada distribuye el control entre los participantes, pero puede dificultar la trazabilidad y la gestión de errores. Cuando el control, la visibilidad y la gestión de excepciones se vuelven imprescindibles, conviene evolucionar hacia una saga orquestada o saga con máquina de estados. Aquí, un componente central mantiene el estado del flujo, decide los pasos siguientes y facilita la observabilidad del proceso.

Soporte de los brokers de mensajes

Algunos brokers como Azure Service Bus (con sesiones), Amazon SQS FIFO (con message groups), Kafka (particiones) o RabbitMQ (single active consumer) ofrecen mecanismos para mantener el orden por clave. Estos ayudan a evitar el procesamiento concurrente por agregado, pero no reemplazan la necesidad de patrones como Outbox, consumidores idempotentes o la modelización explícita de flujos de trabajo cuando los procesos de negocio lo exigen.

Conclusión

La búsqueda del orden de mensajes por agregado en sistemas distribuidos termina, casi inevitablemente, en la implementación de sagas. Al comprender esto, dejamos de luchar contra las colas y diseñamos flujos que realmente responden a las necesidades del negocio, combinando fiabilidad, orden y escalabilidad.

Fuente: Artículo reescrito y adaptado de milanjovanovic.tech.

Compartir:

Más artículos

Novedades de DotNet9 y DotNetMAUI9

Microsoft ha lanzado .NET 9 con mejoras significativas en rendimiento y un enfoque renovado en aplicaciones nativas de la nube. Esta versión STS (Soporte Técnico