Estoy trabajando en una pequeña aplicación de ejemplo para aprender los conceptos de CQRS y el abastecimiento de eventos. Tengo un Basket
agregado y un Product
agregado que debería funcionar de forma independiente.
Aquí hay un pseudocódigo para mostrar la implementación
Basket { BasketId; OrderLines; Address; }
// basket events
BasketCreated { BasketId; }
ItemAdded { BasketId; ProductId; Quantity }
AddItemSucceeded { BasketId; ProductId; Quantity }
AddItemRevoked { BasketId; ProductId; Quantity }
ItemRemoved { BasketId; ProductId; Quantity }
CheckedOut { BasketId; Address }
Product { ProductId; Name; Price; }
// product events
ProductReserved { ProductId; Quantity }
ProductReservationFailed { ProductId; Quantity }
ProductReservationCancelled { ProductId; Quantity; }
Los comandos son bastante similares a los eventos, usan el nombre imperativo y no el tiempo pasado.
En este momento estos funcionan bien independientemente. Emite un comando AddItem
y crea un ItemAdded
evento en el Basket
agregado que hace lo que necesita hacer con el estado de la 'Cesta'. Del mismo modo, para el producto, el comando y los eventos funcionan bien.
Ahora me gustaría combinar esto en un proceso que sería algo así (en términos de comandos y eventos que suceden):
El administrador de procesos haría lo siguiente:
on BasketCreated: CreateShoppingProcess
on ItemAdded: ReserveProduct
on ProductReserved: SucceedAddingItem // does nothing, but needs to be there so that the basket knows it can check out
on ProductReservationFailed: RevokeAddItem
on RemoveItem: CancelProductReservation
on Checkout: CreateOrder // create an order and so on...
Las preguntas a las que no pude encontrar respuestas definitivas son:
- ¿Necesito persistir en el administrador de procesos? Parece que sí, pero no estoy seguro
- Si lo hago, necesito guardar los eventos para el administrador de procesos. Sin embargo, los eventos que está escuchando están vinculados a los agregados. ¿Añado el ID del proceso a esos? ¿Tengo eventos separados solo para el administrador de procesos? Cómo hacer esto y mantenerse lo más SECO posible
- ¿Cómo sé para qué cesta son los
ProductReserved
eventos? ¿Está bien tener unBasketId
sobre eso, o es esa información que se filtra? - ¿Cómo mantengo una relación entre eventos, cómo sé qué
ItemAdded
produjo quéProductReserved
evento? ¿Paso a lo largo de unEventId
? Esto parece extraño ... - ¿Debo implementar el
Basket
como administrador de procesos en lugar de un agregado simple?
Después de un poco más de investigación llegué a esto: una saga es algo que mantiene sus propios eventos y escucha eventos desde el exterior. Básicamente, es un agregado que también puede reaccionar a eventos que suceden fuera de su propio pequeño mundo.
Un administrador de procesos trabaja con los eventos desde el exterior y envía comandos. Su historia se puede reconstruir a partir de los eventos que ocurrieron en los Agregados que comparten un identificador común como un ID de correlación.
fuente
Respuestas:
Revise lo que Rinat Abdullin escribió sobre la evolución del proceso comercial . En particular, observe su recomendación para desarrollar un proceso comercial en un entorno que cambia rápidamente: un administrador de procesos es "solo" un reemplazo automatizado para un ser humano que mira una pantalla.
Mi propio modelo mental de administrador de procesos es que se trata de una proyección de origen de eventos que puede consultar para obtener una lista de comandos pendientes.
Es un modelo de lectura. Puede reconstruir el administrador de procesos a partir del historial de eventos cada vez que lo necesite; o puede tratarlo como una instantánea que actualiza.
No, el administrador de procesos es un administrador . No hace nada útil por sí solo; en su lugar, le dice a los agregados que trabajen (es decir, que realicen cambios en el libro de registro).
Seguro. Nota: en la mayoría de los dominios de compras "reales", no insistiría en reservar inventario antes de procesar un pedido; agrega contención innecesaria al negocio. Es más probable que su empresa quiera aceptar el pedido y luego pedir disculpas en el raro caso de que el pedido no se pueda cumplir en el tiempo requerido.
Los mensajes tienen metadatos; en particular, puede incluir un causationIdentifier (para que pueda identificar qué comandos produjeron qué eventos) y un correlationIdentifier , para rastrear generalmente la conversación.
Por ejemplo, el administrador de procesos escribe su propia identificación como correlationId en el comando; los eventos producidos por una copia del id de correlación del comando, y su administrador de procesos se suscribe a todos los eventos que tienen su propio correlationId.
Mi recomendación es no Pero Udi Dahan tiene una opinión diferente que debes revisar; lo que significa que CQRS solo tiene sentido si sus agregados son sagas : Udi usó la saga en el lugar donde el administrador de procesos se ha convertido en la ortografía dominante.
¿Realmente no? Los administradores de procesos se ocupan principalmente de la orquestación, no del estado del dominio. Una instancia de un proceso tendrá "estado", en forma de un historial de todos los eventos que han observado: lo correcto en respuesta al evento Z depende de si hemos visto eventos X e Y Por lo tanto, es posible que deba poder almacenar y cargar una representación de ese estado (que podría ser algo plano o podría ser el historial de eventos observados).
(Digo "no realmente" porque el agregado se define de forma bastante vaga como para que no sea completamente incorrecto afirmar que la lista de eventos observados es un "agregado". Las diferencias son más semánticas que la implementación: cargamos el estado del proceso y luego decidimos qué mensajes enviar enviar a las partes del sistema responsables del estado del dominio . Aquí se está agitando un poco la mano).
No del todo: la administración del estado no es un hacedor, es un rastreador de guardia. En circunstancias en las que el administrador de procesos no debe emitir ninguna señal, le da conexiones inertes al mundo. En otras palabras,
dispatch(command)
es un no-op.fuente
Lo que estás buscando tiene un patrón llamado "Saga", que es esencialmente un administrador de procesos.
Las Saga también son perfectas para procesos de larga ejecución, ya que puede mantener el estado entre comandos correlacionados.
Aquí hay un gran artículo sobre Sagas
fuente