DDD, Saga y fuente de eventos: ¿Puede una acción de compensación simplemente ser una eliminación en la tienda de eventos?

15

Me doy cuenta de que la pregunta anterior probablemente plantea algunos "¿qué?", ​​Pero déjame intentar explicar:

Estoy tratando de entender un par de conceptos relacionados, básicamente el patrón Saga ( http://www.rgoarchitects.com/Files/SOAPatterns/Saga.pdf ) en combinación con Event-sourcing (A DDD-concept : http://en.wikipedia.org/wiki/Domain-driven_design )

Una buena publicación que lo resume: https://blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-ii-of-ii/

Llegaré a la pregunta en un minuto, pero creo que tengo que intentar resumir lo que entiendo primero (lo cual podría estar mal, así que corríjalo si ese es el caso) ya que esto podría afectar por qué estoy haciendo la pregunta para comenzar:

  1. El patrón Saga es una especie de intermediario que da una acción (usuario final, automatizado, etc., esencialmente cualquier cosa que vaya a cambiar datos) divide esa acción en las actividades comerciales y envía cada una de estas actividades como mensajes a un Bus de mensajes que a su vez lo envía a las raíces agregadas respectivas para que se cuiden.
  2. Estas raíces agregadas pueden operar de manera completamente autónoma (buena separación de preocupaciones, gran escalabilidad, etc.)
  3. Una instancia de Saga en sí no contiene ninguna lógica de negocios, que está contenida en las raíces agregadas a las que envía actividades. La única 'lógica' contenida en la Saga es la lógica de 'proceso' (a menudo implementada como una máquina de estado), que determina en función de las acciones recibidas (así como los eventos de seguimiento) qué hacer (es decir, qué actividades enviar)
  4. Los patrones de Saga implementan una especie de patrón de transacción distribuida. Es decir: cuando una de las raíces agregadas (que de nuevo funciona de manera autónoma, sin saber de las otras existentes) falla, toda la acción podría tener que revertirse.
  5. Esto se implementa al tener todas las raíces agregadas, al finalizar su informe de actividad de nuevo a la Saga. (En caso de éxito y error)
  6. En caso de que todas las raíces agregadas devuelvan un éxito, la máquina de estado interno si la Saga determina qué hacer a continuación (o decide que está hecho)
  7. En caso de falla, la Saga emite a todas las raíces agregadas que participaron en la última acción una llamada Acción de Compensación, es decir: una acción para deshacer la última acción que hizo cada una de las raíces agregadas.
  8. Esto podría ser simplemente hacer un 'Menos 1 voto' si la acción fue "más 1 voto", pero podría ser más complicado como restaurar una publicación de blog en su versión anterior.
  9. El abastecimiento de eventos (consulte la publicación de blog que combina los dos) tiene como objetivo externalizar el almacenamiento de los resultados de cada una de las actividades que cada una de las raíces agregadas lleva a cabo en una Tienda de eventos centralizada (los cambios se denominan 'eventos' en este contexto)
  10. Esta tienda de eventos es la 'versión única de la verdad' y se puede usar para reproducir el estado de todas las entidades simplemente iterando los eventos almacenados (esencialmente como un registro de eventos)
  11. La combinación de los dos (es decir, dejar que las raíces agregadas utilicen el abastecimiento de eventos para externalizar el almacenamiento de sus cambios antes de informar a la Saga) permite muchas posibilidades interesantes, una de las cuales se refiere a mi pregunta ...

Sentí que necesitaba sacar esto de mi hombro, ya que es mucho de entender de una vez. Dado este contexto / mentalidad (de nuevo, corrija si está equivocado)

la pregunta: cuando una raíz agregada recibe una Acción compensatoria y si esa raíz agregada ha subcontratado sus cambios de estado utilizando el abastecimiento de eventos, ¿no sería la Acción compensatoria en todas las situaciones simplemente una eliminación del último evento en el Almacén de eventos para eso? dada la raíz agregada? (Suponiendo que la implementación persistente permite eliminaciones)

Eso tendría mucho sentido para mí (y sería otro gran beneficio de esta combinación), pero como dije, podría estar haciendo estas suposiciones basadas en una comprensión incorrecta / incompleta de estos conceptos.

Espero que esto no sea demasiado largo.

Gracias.

Geert-Jan
fuente

Respuestas:

9

No debe eliminar los eventos de su tienda de eventos. Estos representan algo que sucedió. Si algo sucede ahora, entonces también debería saberlo, por lo tanto, agregue un evento que obligue a su agregado a volver a algún estado anterior. Es una pena eliminar información de su base de datos.

Piense en el ejemplo del carrito de Greg Young y los artículos eliminados. Puede ser mañana, la información de la acción compensatoria puede ser de cualquier valor.

En cuanto a la saga, todo es correcto, hasta donde yo sé. Debes pensar en la saga como una máquina de estado. Solo hace eso.

Es un comando que la saga está emitiendo para decirle al agregado que haga algo. De esta acción habrá un evento. Este evento puede ser la acción correctiva que necesita, o puede que tenga que ser denormalizado en una vista para que algún usuario lo vea y decida qué hacer.

Depende de las reglas de su negocio. O bien, hay una solución fácil: la raíz agregada sabe que en ese caso, usted hace eso, o la elección es demasiado compleja para hacerse mediante programación (el costo de desarrollo es demasiado alto) y, por lo tanto, puede proponer esto a algún usuario, que podría elegir entre diferentes acciones. Todo depende del contexto de la acción compensatoria. Estas son reglas comerciales puras. ¿Qué debemos hacer en este caso o en ese caso? Esto es algo que debe preguntarle a su experto en dominios, y luego elegir con él, si es mejor desarrollar una solución automática o si la solución es preguntarle al usuario Ronald R., porque él suele responder a esta pregunta por lo general.

Arthis
fuente
¿Cómo sabría el agregado a qué estado revertir? ¿Se le permitirá consultar en la tienda de eventos o algo así?
Geert-Jan
No debe revertirse, sino agregar otro evento. Es un comando que la saga está emitiendo para decirle al agregado que haga algo. De esta acción habrá un evento.
Arthis
Si yo entiendo. "Revertir" probablemente fue mal elegido. Considere lo siguiente: es posible que desee utilizar Event Sourcing with Sagas para modelar, entre otras cosas, flujos de publicación / aprobación de documentos. ¿Qué sucede si un editor ha enviado una acción ChangeBlogBody que finalmente persiste como un evento BlogBodyChanged a la Tienda de eventos? Posteriormente, por alguna razón, se emite una Acción de compensación. ¿Cómo sabría el Agregado qué evento de compensación para disparar que da como resultado el contenido del Cuerpo del Blog tal como era justo antes de que se emitiera la acción ChangeBlogBody?
Geert-Jan
Depende de las reglas de su negocio. O bien, hay una solución fácil: la raíz agregada sabe que en ese caso, usted hace eso, o la elección es demasiado compleja para hacerse mediante programación (el costo de desarrollo es demasiado alto) y, por lo tanto, puede proponer esto a algún usuario que podría elegir entre diferentes acciones.
Arthis
Todo depende del contexto de la acción compensatoria. Estas son reglas comerciales puras. ¿Qué debemos hacer en este caso o en ese caso? Esto es algo que debe preguntarle a su experto en dominios, y luego elegir con él, si es mejor desarrollar una solución automática o si la solución es preguntarle al usuario Ronald R., porque él suele responder a esta pregunta por lo general.
Arthis
6

Para completar, pensé incluir un fragmento relevante de Martin Fowler sobre formas de revertir el estado:

Además de los eventos que se juegan hacia adelante, a menudo también es útil que puedan revertirse.

La reversión es la más directa cuando el evento se presenta en forma de diferencia. Un ejemplo de esto sería "agregar $ 10 a la cuenta de Martin" en lugar de "establecer la cuenta de Martin a $ 110". En el primer caso, puedo revertir simplemente restando $ 10, pero en el último caso no tengo suficiente información para recrear el valor pasado de la cuenta.

Si los eventos de entrada no siguen el enfoque de diferencia, entonces el evento debe garantizar que almacena todo lo necesario para la reversión durante el procesamiento. Puede hacer esto almacenando los valores anteriores en cualquier valor que se cambie, o calculando y almacenando las diferencias en el evento.

De: http://martinfowler.com/eaaDev/EventSourcing.html

Geert-Jan
fuente
1

Conceptualmente:

  • El evento es algo que sucedió. El pasado no puede ser cambiado.
  • El comando es algo que hacer. El comando puede no suceder (puede ser rechazado).

Solo podemos cambiar nuestro estado futuro ejecutando otro comando (Compensar acción) que debería provocar que los eventos cambien el estado de la aplicación.

Para "confundir" la pregunta, piense en esta frase "eliminar del último evento":

  • ¿Qué sucede si el último evento no es el que debe eliminarse? ¿Qué sucede si ocurrieron otros eventos después del que se eliminará? Estos eventos también deben cambiarse (ya que su estado base habría cambiado al eliminar el evento anterior).
  • ¿Qué pasa si el evento se envió al sistema externo? Es posible que no tenga acceso para corregir su estado que no sea enviar otro evento.

En resumen, no tiene la opción de eliminar eventos dentro del patrón CQRS.

Puede reducir su Tienda de eventos haciendo un estado de instantánea (que se basa en todos los eventos que conducen a ese estado), pero este aspecto físico no tiene nada que ver con el concepto de evento.

uvsmtid
fuente
0

Geert-Jan, yo también creo que la acción de compensación simplemente puede eliminar los eventos correspondientes. Tiene sentido y muestra otro beneficio del patrón de diseño de Event Sourcing: una implementación más fácil del patrón de diseño de Compensación de transacciones.

Algunos dicen que eliminar el evento viola los "principios" del abastecimiento de eventos o CQRS. Creo que es una generalización limitante. Creo que está bien eliminar un evento si se creó dentro del alcance de una transacción global que se está cancelando. Considere el pseudocódigo:

try {
    newEvents = processMycommand(myCommand)
    for (Event newEvent : newEvents)
        EventStore.insertEvent(newEvent);
} catch (Exception e) {
    EventStore.rollback();
}

Supongamos que su tienda de eventos es una base de datos transaccional. En el pseudocódigo, puede imaginar la situación en la que insertó el primer evento, pero al intentar insertar el segundo evento se produjo una excepción. El comando de reversión revertiría naturalmente la inserción del primer evento. ¿Es eso razonable?

Si es razonable para una transacción de base de datos ACID (transacción con confirmación / reversión), ¿por qué no sería razonable para una transacción compensatoria?

Al ejecutar la transacción global de Saga, los cambios de datos se pueden deshacer (por compensación). No es necesario mantener el evento que se creó durante la transacción porque la transacción no se completó.

Ahora, si la compensación intenta eliminar un evento y ese evento no es el evento más nuevo en un objeto, entonces la eliminación no debería ocurrir. Pero, en general, es poco probable que suceda, especialmente en soluciones de lectura intensiva.

Paulo Merson
fuente
0

Juguemos con la idea de que el almacenamiento de eventos son solo datos que desea guardar. Por ejemplo, podemos tener un disco duro, podemos comenzar desde el principio y escribir datos en él. Cada vez que tenemos un evento, agregamos nuestros datos anteriores, así que seguimos escribiendo en el disco donde nos detuvimos la última vez. Cuando queremos eliminar un evento, volvemos, eliminamos esa parte del disco y dejamos un espacio. Retroceder por sí solo ralentiza nuestro almacenamiento de eventos, pero podemos vivir con eso. Si usamos un sistema de archivos, eso intentará llenar el vacío con los últimos eventos, por lo que terminaremos teniendo un almacenamiento fragmentado lento o podemos hacer la desfragmentación. Ninguno de los dos es algo que nos gusta. Si hablamos de bases de datos, obtendrá esto si usa una base de datos relacional en lugar de una base de datos de agregar solo para almacenar sus eventos:

ingrese la descripción de la imagen aquí ref: https://cambridge-intelligence.com/bringing-time-series-data-to-life-with-keylines/

De c. por un sitio normal esto no importa, pero estas soluciones están diseñadas para grandes sitios web como Facebook, Google, etc. Así que realmente la pregunta no tiene sentido, porque ¿cómo eliminaría un evento en una base de datos de solo agregar y cómo ¿Llamas compensación a algo así como construir una máquina del tiempo y retroceder en el tiempo para cambiar o prevenir un evento?

Hasta donde se. la única forma de resolver esto es creando un nuevo almacenamiento de eventos donde excluya los eventos que no desea tener y luego elimine el almacenamiento de eventos anterior. Pero esta es una solución extrema para eliminar un solo evento. Si hablamos de GDPR, entonces la única solución relativamente buena que conozco es almacenar datos personales cifrados en el almacenamiento de eventos y eliminar la clave de cifrado de una base de datos diferente.

inf3rno
fuente