Cómo implementar un administrador de procesos en el abastecimiento de eventos

14

Estoy trabajando en una pequeña aplicación de ejemplo para aprender los conceptos de CQRS y el abastecimiento de eventos. Tengo un Basketagregado y un Productagregado 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 AddItemy crea un ItemAddedevento en el Basketagregado 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:

  1. ¿Necesito persistir en el administrador de procesos? Parece que sí, pero no estoy seguro
  2. 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
  3. ¿Cómo sé para qué cesta son los ProductReservedeventos? ¿Está bien tener un BasketIdsobre eso, o es esa información que se filtra?
  4. ¿Cómo mantengo una relación entre eventos, cómo sé qué ItemAddedprodujo qué ProductReservedevento? ¿Paso a lo largo de un EventId? Esto parece extraño ...
  5. ¿Debo implementar el Basketcomo 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.

Ivan Pintar
fuente
Parece que está intentando codificar en su sistema un proceso formal que parafrasea un caso de uso informal existente hecho de una serie de comandos. Al hacerlo, parece que está creando una serie de comandos y eventos redundantes además de los existentes. ¿Esa es tu intención? ¿Cuál es la necesidad comercial detrás de formalizar las cosas como un proceso en código? ¿Qué en su dominio requiere que identifique este proceso y razone al respecto como un concepto completo?
guillaume31
Este es un proyecto totalmente inventado donde el objetivo es aprender a hacer que dos agregados relativamente independientes trabajen juntos. Así que realmente no hay una verdadera "necesidad comercial", y estoy tratando de evitar la redundancia en estos comandos y eventos tanto como sea posible. De ahí la confusión con el administrador de procesos., Porque parece que no debería repetir cosas que los agregados ya están manejando. Sin embargo, necesito mantener una conexión entre estos dos agregados de alguna manera. Parece que usar la causalidad y la correlación podría ayudar, pero necesito probarlo.
Ivan Pintar

Respuestas:

14

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.

¿Necesito persistir en el administrador de procesos? Parece que sí, pero no estoy seguro

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.

Si lo hago, necesito guardar los eventos para el administrador de procesos.

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).

¿Cómo sé para qué cesta son los eventos de ProductReserved? ¿Está bien tener un BasketId en esos también, o es esa información que se escapa?

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.

¿Cómo mantengo una relación entre eventos, cómo sé qué ItemAdded produjo qué evento de ProductReserved?

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.

¿Debo implementar Basket como un administrador de procesos en lugar de un agregado simple?

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.

deberían los gerentes de proceso recuperar agregados?

¿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).

Entonces, ¿el PM no necesita usar un tipo de gestión estatal sobre otro porque solo es responsable de hacer cosas en vivo y nunca durante las repeticiones?

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.

VoiceOfUnreason
fuente
1
Usted dice: puede reconstruir el administrador de procesos a partir del historial de eventos cada vez que lo necesite ... Pero para reconstruirlo, necesito guardar eventos para él. ¿O debería reconstruirlo a partir de los eventos en los agregados? La parte con la que estoy luchando es: con los agregados, los eventos tienen la identificación agregada, y es fácil de reconstruir al encontrar todos los eventos con esa identificación agregada. Pero, ¿cómo haría eso para el administrador de procesos? ¿Debería estar haciendo eso para el administrador de procesos? ¿O debería el administrador de procesos buscar los agregados cuando necesita decidir algo basado en un evento que se produjo?
Ivan Pintar
Lo que me faltaba era la noción de causalidad y correlación en el abastecimiento de eventos. Una vez que lo examiné, tu respuesta a la cuarta pregunta finalmente tuvo sentido.
Ivan Pintar
1
Me encantaría recibir una respuesta al primer comentario de @IvanPintar; deberían los gerentes de proceso recuperar agregados? ¿Deberían construir los suyos basados ​​en los eventos que procesa? En ese caso, los controladores de eventos deberían estar libres de efectos secundarios, ¿verdad?
Jeff
@Jeff En un ejemplo que hice, el administrador de procesos tenía su propio almacenamiento que se actualizaba con cada evento procesado, una especie de modelo de lectura. Esto fue simple de hacer y fue fácil rastrear lo que ya se procesó. En otro ejemplo, el administrador de procesos creó y almacenó sus propios eventos, basados ​​en los eventos agregados. Similar a lo anterior, pero el estado fue de origen de eventos. Dependiendo de la complejidad del estado que mantiene el administrador de procesos, puede ser más fácil hacer uno u otro. Encontré el primer enfoque más simple.
Ivan Pintar
Interesante, ¿entonces depende más o menos del desarrollador siempre que el administrador de procesos responda a los eventos y envíe los comandos al final?
Jeff
2

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

Bishoy
fuente