2011-09-05 8 views
12

Non riesco a capire cosa dovrebbe succedere quando si ricostruisce il modello ripetendo gli eventi da EventStore, in particolare quando gli eventi possono far scattare altri eventi.Event Sourcing: eventi che attivano gli altri e lo stato di ricostruzione

Ad esempio, un utente che ha effettuato 10 acquisti deve essere promosso a un cliente preferito e ricevere un'e-mail che offre determinate promozioni.

Evidentemente non vogliamo che l'e-mail venga inviata ogni volta che ricostruiamo il modello per quell'utente, ma come possiamo evitare che ciò accada quando riproduciamo il nostro decimo PurchaseMadeEvent?

risposta

8

Gli eventi concatenati possono essere molto complessi e facilmente senza controllo, quindi eviterei il più possibile. Ad esempio nello scenario che stai descrivendo vorrei aumentare un UserPromotedEvent (magari utilizzando anche lo PromoteUserCommand), tuttavia non considererei l'invio fisico/fisico di un'email come parte del mio dominio. Invece creerei un gestore/denormalizzatore aggiuntivo per UserPromotedEvent che registrerebbe la necessità di inviare l'email con alcuni controlli addizionali abbastanza probabilmente. Successivamente, un altro processo raccoglierà le informazioni di e-mail non ancora elaborate e le invierà. Questo approccio attenuerebbe i problemi che potrebbero verificarsi con gateway di posta elettronica non accessibile/scalabile.

In generale, la necessità di concatenare eventi spesso indica che è necessario implementare un Saga per il processo.

2

Quando si ripetono gli eventi, non si riproduce tutta la logica del dominio associata alla generazione di tali eventi. Solitamente nel tuo metodo di dominio puoi generare un evento; l'innalzamento di quell'evento dovrebbe quindi aggiornare lo stato generale di quell'oggetto dominio.

Ad esempio:

public class Purchase { 
    private int _id; 
    private string _name; 
    private string _address; 
    private double _amount; 

    public Purchase(int id, string name, string address) { 
    //do some business rule checking to determine if event is raised 

    //perhaps send an email or do some logging 
    //etc. 
    if (should_i_raise_event) { 
     ApplyEvent(new PurchaseMadeEvent() { 
     ID = id, 
     Name = name, 
     Address = address 
     }); 
    } 
    } 

    public UpdatePurchase(int id, double amount) { 
    //more checking to see if event is to be raised 
    if (should_i_raise_event) { 
     ApplyEvent(new PurchaseUpdatedEvent() { 
     ID = id, 
     Amount = amount 
     }); 
    } 
    } 

    protected void OnPurchaseMade(PurchaseMadeEvent e){ 
    _id = e.ID; 
    _name = e.Name; 
    _address = e.Address; 
    } 

    protected void OnPurchaseUpdated(PurchaseUpdatedEvent e){ 
    _id = e.ID; 
    _amount = e.Amount; 
    } 
} 

In questo esempio, quando i miei eventi vengono riprodotti, il gestore di eventi OnPurchaseMade otterrà eseguito, non il costruttore dell'oggetto dominio. Lo stesso con lo PurchaseUpdatedEvent - il suo gestore di eventi verrà eseguito, non il metodo di dominio che ha generato l'evento.

L'evento contiene tutto ciò che è necessario per aggiornare il modello di dominio (e applicare gli aggiornamenti al modello di lettura). I metodi di dominio che vengono eseguiti ti portano al punto che un evento può essere sollevato.

Spero che questo aiuti. Fammi sapere se ho bisogno di fornire ulteriori informazioni.

Buona fortuna !!

6

Non si dovrebbe aumentare l'evento dal gestore eventi: non farlo! Dovresti usare invece sagas.

Nel tuo caso, saga si abbona per PurchaseMadeEvent e genera il COMANDO PromoteCustomer, che provoca l'evento CustomerPromoted. Ancora una volta, c'è un'altra saga che si iscrive all'evento CustomerPromoted e invia il comando SendEmailToPromotedCustomer. Quando si riproducono eventi, non iscriversi saga per l'evento CustomerPromoted.

Questo è tutto sulla differenza tra comando ed evento. È importante capirlo. Gli eventi raccontano cosa è già successo, i comandi dicono cosa accadrà.

+0

Mi rendo conto che questa è una risposta piuttosto vecchia, ma come sarebbe possibile che la Saga emettesse un comando 'PromoteCustomer' quando riceve un' PurchaseMadeEvent'?Ciò si basa (come da descrizione del PO) sul fatto che il cliente abbia effettuato 10 acquisti, che è la logica di dominio che la Saga non dovrebbe contenere. Forse spara sempre un 'TestToPromoteCustomer' e lascia che l'aggregato faccia il check per fare effettivamente la promozione? Questo sembra un po 'maldestro però .. Grazie per qualsiasi intuizione –

+0

Sì, hai ragione, la saga dovrebbe inviare comandi TestToPromoteCustomer. Penso che sia assolutamente OK sacrificare la purezza per la manutenibilità. – xelibrion