para - popular architecture tags
¿Deberían surgir eventos de dominio dentro o fuera de una transacción? (2)
En nuestra aplicación, generamos eventos de dominio cuando algo cambia en el modelo de dominio. Algunas de las tareas que realizan los controladores de eventos deben realizarse dentro de la misma transacción que se usó cuando se genera el evento, otras tareas deben realizarse fuera de esta transacción.
Por ejemplo,
Cuando se agrega una línea de pedido a una entidad de pedido, se genera el evento de dominio OrderLineAdded, un evento de dominio cambia el estado del modelo de dominio (por lo que debe realizarse en la misma transacción), luego, cuando se completa la transacción, se debe actualizar la interfaz de usuario.
¿Cómo abordarías este problema?
- Provoca dos eventos, uno dentro de la transacción y otro fuera de la transacción.
- ¿Desea aumentar el evento dentro de la transacción, pero usa el controlador de eventos para enviar una solicitud Async para actualizar la interfaz de usuario?
La opción 1 parece confusa, ya que los nombres de los eventos deben transmitir de alguna manera que están dentro o fuera de una transacción, pero con los controladores de la opción 2 del evento de dominio siempre se debe asumir que se llaman de forma sincrónica desde una transacción.
Tal vez hay un mejor enfoque?
Creo que ambos enfoques podrían ser buenos, solo mantén el mismo enfoque en cada parte de tu código:
- necesitará dos (o más) controladores de eventos, uno para el contexto del modelo de dominio que está dentro del alcance de la transacción y otro para los contextos auxiliares, como la interfaz de usuario. Su código de dominio no debe preocuparse por lo que hacen otras partes del código, solo notifíqueles sobre el cambio en los datos del dominio.
- el método del controlador de eventos del código de dominio puede enviar eventos asíncronos a la interfaz de usuario u otros módulos. Los eventos del dominio deben ser sincrónicos, de lo contrario, necesitarías dos fases para mantener la transaccionalidad.
Personalmente, me gusta la opción 2 más, porque mantiene el código de dominio más limpio y al usar la comunicación asíncrona, el núcleo y otros módulos se desacoplarán, por lo que los problemas en los módulos externos no dificultarán el funcionamiento del núcleo. Por otro lado, puede haber circunstancias en las que la opción 1 sea más ventajosa.
He tenido un problema similar. El modelo de dominio fue la publicación de eventos (utilizando la técnica que Udi Dahan describe here ). Luego me di cuenta de que mis controladores relacionados con la IU se invocan incluso si algo sale mal y la transacción se revierte más tarde.
Para solucionar esto, introduje otra función en el sistema, otro tipo de controlador de eventos. Tengo ITransactionalEventHadneler
y INonTransactionalEventHandler
. Los primeros se invocaron de forma sincrónica inmediatamente en el método DomainEvents.Publish()
. Los últimos se pusieron en cola para ser invocados tan pronto como la transacción se confirme (utilizando los enganches System.Transactions). La solución funcionó bien y fue bastante legible y mantenible.