2012-06-13 8 views
12

Esempio: Le regole aziendali indicano che il cliente deve ricevere un messaggio di conferma (e-mail o simile) quando viene effettuato un ordine.CQRS - Quando inviare un messaggio di conferma?

Diciamo che uno NewOrderRegisteredEvent viene inviato dal dominio ed è raccolto da un listener di eventi che invia il messaggio di conferma. Quando ciò viene fatto, un altro gestore di eventi genera un'eccezione o qualcos'altro va storto e l'unità di lavoro viene ripristinata. Ora abbiamo inviato all'utente un messaggio di conferma per qualcosa che è stato ripristinato.

Qual è il modo "cqrs" per risolvere problemi come questo in cui si vuole fare qualcosa dopo aver commesso un'unità di lavoro? Un altro fattore complicante è la ripetizione degli eventi. Non voglio che i vecchi messaggi di conferma vengano nuovamente inviati ogni volta che rieseguo gli eventi registrati per creare una nuova vista/proiezione.

La mia migliore teoria fino ad ora: ho appena iniziato a esaminare l'affascinante mondo dei cqrs e mi chiedevo se questo sarebbe stato implementato come una saga? Se una saga è come una macchina a stati in cui ogni transizione può avvenire solo una volta, immagino che risolverebbe questo problema? Ho solo un momento difficile visualizzare come questo si adatta insieme con gli eventi del bus di comando e dominio ..

+1

Compilare all'attività "invia e-mail" un messaggio. Se il rotolo torna indietro, lo stesso vale per l'invio del messaggio (per una conservazione duratura). Qualcos'altro preleva il messaggio e fa l'e-mail. A proposito, non correlati. Semplice senso del calcolo distribuito. –

+0

Come per la replica dell'evento, MAI induce questo tipo di comportamento. Se il tuo impl. sì, lo stai facendo male. –

+0

Questo ha senso, ma mi interessa questo in un contesto cqrs. Cos'è un "messaggio"? E chi/cosa lo prenderebbe a, e quando? Sarebbe bello sfruttare l'event store per evitare l'introduzione di un altro meccanismo di archiviazione per tenere traccia delle comunicazioni in uscita. – Kimble

risposta

16
  1. Un evento deve verificarsi solo dopo che la transazione è stata completata. Se qualcosa va storto e c'è un rollback, allora l'evento non si è verificato da un punto di vista esterno. Pertanto non dovrebbe essere pubblicato affatto. Anche se un evento OrderRegistrationFailed potrebbe essere pubblicato, se necessario.

  2. Non si desidera che la posta venga inviata a meno che il comando non sia stato eseguito correttamente.

    Prima alcuni motivi per cui il gestore di comandi, come proposto in un'altra risposta, sarebbe il posto sbagliato: in alcune circostanze il gestore comandi non sarebbe in grado di stabilire se il comando alla fine riuscirà o meno. Avere che il gestore comandi invoca l'invio di posta metterebbe anche le conoscenze di processo all'interno del gestore comandi, il che interromperà l'SRM e accoppierà troppo strettamente le regole aziendali con il livello dell'applicazione.

    La posta deve essere inviata dopo il fatto, ad esempio da un gestore eventi.

    Per impedire a questo gestore di sparare durante la riproduzione, non è possibile registrarlo. Funziona in modo simile a come testate la vostra applicazione. Si registrano solo i gestori effettivamente necessari.

    sistema
    • Produzione -> registrare tutti i gestori di eventi
    • Test -> registrare solo i gestori di eventi testati
    • Replay -> registrare solo i gestori di proiezione/denormalizzazione

altro - ancor più sciolto, anche se un po 'più complesso, la possibilità sarebbe quella di avere un Saga gestire lo NewOrderRegisteredEvent e inviare un comando SendMail all'approccio contesto limitato e opaco (grazie, Yves Reynhout, per averlo indicato nei commenti della domanda).

+1

Questa è una delle migliori risposte che ho ottenuto su StackOverflow! Quindi gli eventi di dominio saranno memorizzati in un buffer da qualche parte e pubblicati solo al di fuori del dominio (a proiezioni/de-normalizzatori) una volta che gli eventi sono stati scritti correttamente nel registro eventi? Immagino che scrivere sull'archivio eventi avvenga all'interno di una transazione (di solito) inizializzata da un gestore di comandi/intercettore? – Kimble

+0

Fondamentalmente sì, la memorizzazione di uno o più eventi/i (in un registro eventi o in un archivio eventi, fare attenzione a non confondere i due) sarebbe l'ultima parte della transazione. Solo dopo averlo memorizzato correttamente, verranno inviati ed elaborati, possibilmente anche in modo asincrono. –

+0

Qual è la differenza tra un registro eventi e un negozio? Sono abbastanza sicuro di aver visto quelli usati in modo intercambiabile durante la lettura di cqrs. – Kimble

2

Ci sono due possibili soluzioni

1) La pubblicazione della manifestazione e la gestione della manifestazione (ad esempio l'e-mail) fanno parte di un'unica transazione. In questo caso, il framework delle transazioni si prende cura di te per te. Se l'email non riesce, l'evento viene ripristinato. Probabilmente riproverai il comando. Questo è concettualmente pulito e facile da pensare. Nessun evento è finito di pubblicare fino a quando tutti quelli che hanno qualcosa da dire a riguardo hanno espresso la loro opinione. Tuttavia, in pratica, questo può essere doloroso, in quanto comporta in genere transazioni distribuite. Questi sono difficili da trovare. Il tuo client di posta elettronica può iscriversi alla stessa transazione del database che ospita i tuoi eventi?

2) La pubblicazione dell'evento è transazionale, ma i gestori di eventi gestiscono ciascuna le transazioni a modo loro. Il gestore eventi che invia le email potrebbe tenere traccia di quali eventi ha visto. Se si arrestasse in modo anomalo, richiederebbe vecchi eventi ed elaborarli. Potresti prendere una decisione aziendale su quanto sarebbe importante se le persone manchino o duplichino email. (Per le transazioni relative al denaro, probabilmente la risposta non dovrebbe essere consentita.)

La soluzione (2) è in genere ciò che viene promosso nei cerchi DDD/CQRS in quanto è la soluzione più sciolta. La soluzione (1) è abbastanza pratica in un piccolo sistema in cui l'archivio degli eventi e le proiezioni si trovano in un unico database e le proiezioni non cambiano spesso. La soluzione (2) consente a una varietà di gestori di eventi di funzionare a modo loro. La soluzione (1) può causare un sacco di problemi non sovrapposti per diventare entagled. In questo caso le regole aziendali dell'ordine non vengono completate fino a quando non vengono prese in considerazione le molte cose bizzarre che si verificano nell'e-mailing. Per prima cosa, potrebbe rallentarti un po '.

Se l'invio dell'e-mail era più interessante di "ha visto l'evento, ha inviato l'e-mail", allora hai ragione, potresti avere una saga o un flusso di lavoro nelle tue mani. L'e-mail in operazioni di grandi dimensioni è spesso un sistema complesso a sé stante che è improbabile che tu debba implementare molto di. Devi solo essere sicuro di mettere la tua e-mail in una coda di richieste di qualche tipo (usando approccio (2)), e il sistema email probabilmente farà tentativi/batch/evitamento dello spam/lavoro durante la notte/ecc.

+0

Grazie per la lunga risposta! Le transazioni distribuite sono un dolore. Per quanto riguarda la soluzione numero due, ciò comporterebbe l'introduzione di un nuovo meccanismo di archiviazione per tenere traccia delle e-mail che ha inviato, oppure è comune sfruttare l'archivio eventi anche per questo? Vedo alcuni potenziali problemi con i gestori di eventi che pubblicano i propri eventi .. Soprattutto durante una riproduzione in cui l'evento "email inviata x" viene dopo l'evento che ha innescato l'email in primo luogo. – Kimble

+0

Se vuoi veramente inviare e-mail transazionali, allora dovrai gestirlo in qualche modo. Forse salvando l'identità di un'email che hai inviato con successo sul disco.Ma la maggior parte delle operazioni di posta elettronica di qualità commerciale non garantiscono la consegna se si scrive il messaggio necessario in qualche coda? –

+0

L'invio di e-mail transazionali veramente è fuori dal campo d'azione adesso. Ero solo curioso di sapere come questo problema è stato risolto in cqrs, specialmente in concomitanza con la riproduzione dell'evento. Ma sì, posizionare l'e-mail su una coda e archiviare un id di correlazione nell'archivio eventi sarebbe stato un lungo passo per garantire la consegna. – Kimble

Problemi correlati