CQRS + Abastecimiento de eventos: (¿es correcto que) Los comandos generalmente se comunican punto a punto, mientras que los eventos de dominio se comunican a través de pub / sub?

12

Básicamente estoy tratando de entender el concepto de CQRS y conceptos relacionados.

Aunque CQRS no necesariamente incorpora la mensajería y la búsqueda de eventos, parece ser una buena combinación (como se puede ver con muchos ejemplos / publicaciones de blog que combinan estos conceptos)

Dado un caso de uso para un cambio de estado para algo (por ejemplo, para actualizar una Pregunta sobre SO), ¿consideraría que el siguiente flujo es correcto (como en la mejor práctica)?

El sistema emite un UpdateQuestionCommand agregado que se puede separar en un par de comandos más pequeños: UpdateQuestion que está dirigido a la raíz agregada de la pregunta y UpdateUserAction (para contar puntos, etc.) dirigido a la raíz agregada del usuario. Estos se envían de forma asincrónica utilizando mensajes punto a punto.

Las raíces agregadas hacen lo suyo y, si todo va bien, activan los eventos QuestionUpdated y UserActionUpdated respectivamente, que contienen el estado que se subcontrata a una tienda de eventos ... para ser persistido yadayada, solo para ser completo, no es realmente el punto aquí.

Estos eventos también se colocan en una cola de pub / sub para su difusión. Cualquier suscriptor (entre los que probablemente uno o varios proyectores que crean las vistas de lectura) es libre de suscribirse a estos eventos.

La pregunta general: ¿es realmente la mejor práctica, que los comandos se comuniquen punto a punto (es decir: el receptor es conocido) mientras que los eventos se transmiten (es decir, se desconocen los receptores)?

Suponiendo lo anterior, ¿cuál sería la ventaja / desventaja de permitir que los comandos se transmitan a través de pub / sub en lugar de punto a punto?

Por ejemplo: al transmitir Comandos mientras se usa Saga, podría ser un problema, ya que el papel de mediación que una Saga debe jugar en caso de falla de una de las raíces agregadas se ve obstaculizado, porque la saga no sabe qué raíces agregadas participan para comenzar. .

Por otro lado, veo ventajas (flexibilidad) cuando se permite transmitir comandos.

Geert-Jan
fuente
Pregunta bien escrita por cierto.
Dav

Respuestas:

19

Descargo de responsabilidad: solo estoy dando mis primeros pasos en el mundo CQRS, pero puedo ofrecer mi comprensión actual del asunto y veremos si otros lo confirman. Todo lo que escribo a continuación tiene un tema subyacente "tal como lo veo", y no tiene autoridad.

El caso del 80%

Para responder a su pregunta, los comandos son de hecho un asunto punto a punto. Cuando un comando ingresa a un controlador (aplicación web MVC), ese controlador le pide al despachador de comandos que encuentre uno y solo un controlador de comando apropiado, y delega el trabajo a ese controlador.

¿Por qué no publicar?

Es una cuestión de responsabilidad . Si algo envía una orden, implica la expectativa de que se cumplirá. Si simplemente publica y espera que algo en algún lugar lo tome y actúe en consecuencia, no hay garantía de que este sea el caso. Por extrapolación, tampoco sabe si varios controladores no deciden actuar sobre un comando, lo que posiblemente resulte en que el mismo cambio se aplique más de una vez.

Los eventos, por otro lado, son de naturaleza informativa, y es razonable esperar que cero, dos o más componentes estén interesados ​​en un evento en particular. Realmente no nos importa el alcance de realizar el cambio solicitado.

Ejemplo

Esto podría compararse con la vida real. Si tiene tres hijos, entre a una habitación y simplemente grite "Limpia el baño", no tienes ninguna garantía de que alguien lo haga, y quizás no se haga dos veces (si tienes hijos obedientes, eso es ;-) Debes les irá mejor si asigna a un niño específico para que haga lo que quiere hacer.

Sin embargo, cuando ese niño termina su trabajo, es conveniente si grita "se ha limpiado el baño", para que todos los que quieran cepillarse los dientes sepan que ahora pueden hacerlo.

Dav
fuente
Tiene mucho sentido. Excelente analogía :)
Geert-Jan
Me perdiste en ... When a command enters a controller (MVC webapp)-? ¿Estás usando RESTful? o algunos puntos finales de API híbridos? ¿Podría agregar un ejemplo, por favor?
Piotr Kula
@ppumkin utilizamos un punto final WebAPI al que llamaría nuestra aplicación web cada vez que necesitara ejecutar un comando. P.ej. si el usuario quisiera agregar un comentario de publicación, la aplicación web enviaría una solicitud POST a example.com/api/Post/AddPostComment.
Dav
1

Estoy de acuerdo en que un sistema iniciador generalmente nunca esperaría que un comando sea tramitado por múltiples sistemas de destino:

  • Por lo general, los comandos nunca se 'envían y rezan': el sistema iniciador de un comando generalmente desea retroalimentación asíncrona a medida que se produce el progreso y el resultado del comando (por ejemplo, eventos de estado como acknowledgementexitosos completiono failurepueden ser publicados por el sistema objetivo para informar al iniciador sistema).
  • Si se involucraran múltiples sistemas de destino, el sistema iniciador recibiría múltiples resultados (posiblemente contradictorios) para el comando (por ejemplo, el objetivo 1 tuvo éxito, pero el objetivo 2 falló). Esto requeriría una complejidad adicional para determinar el estado real del comando original (por ejemplo, ¿la transacción del comando se consideraría exitosa solo si todos los objetivos tuvieron éxito? ¿Debería el comando retroceder o compensarse en los objetivos exitosos si uno de los objetivos fallara? etc.) Esto introduciría un acoplamiento y una complejidad indeseables entre los sistemas iniciador y objetivo.

Sin embargo, todavía tiene sentido poder suscribir consumidores adicionales (no transaccionales y, por lo general, bastante "promiscuos") que "escuchan" los comandos emitidos entre sistemas.

  • Propósitos de auditoría
  • Instrumentación y métricas operativas (por ejemplo, carga, análisis de negocios, etc.)
  • Procesamiento de eventos complejos o `` escuchas '' de procesamiento de eventos continuos: estos sistemas pueden detectar errores o irregularidades en los comandos (por ejemplo, la frecuencia de los comandos o la correlación entre diferentes combinaciones de comandos y eventos), y pueden activar alertas o acciones correctivas (a menudo en el forma de más, diferentes tipos de comandos).
StuartLC
fuente