Come gestire gli effetti collaterali in CRQS durante la riproduzione di eventi?

10

Si dice che in CQRS è facile correggere un bug, ridistribuire e quindi riprodurre gli eventi.

Ma, se uno degli eventi dovesse causare un sistema esterno non nel tuo controllo per "spedire un oggetto" al cliente se semplicemente riesegui gli eventi, l'articolo verrebbe spedito due volte.

Come lo risolvi?

    
posta Jas 10.06.2017 - 12:31
fonte

3 risposte

6

È necessario stabilire una chiara separazione tra gli eventi che modificano lo stato del modello letto e gli eventi (potenzialmente) che modificano lo stato dei sistemi esterni. Assicurati di non avere nessun "evento misto" che modifichi entrambi gli stati insieme. In questo modo, puoi riprodurre i tuoi eventi in una specifica "modalità di riproduzione" in cui quegli eventi per il sistema esterno non vengono nuovamente attivati. In questa modalità, puoi anche "simulare" tutti gli eventi originariamente avviati dal sistema esterno (ora li prendi invece dalla coda di riproduzione).

Non dimenticare, il passo di ridistribuzione significa in realtà per ripristinare lo stato del modello letto in un momento precedente. Questo probabilmente non è nulla che tu possa fare (o dover fare) per lo stato dei sistemi esterni.

    
risposta data 10.06.2017 - 13:06
fonte
3

Dall'articolo event sourcing di Martin Fowler:

The fundamental idea of Event Sourcing is that of ensuring every change to the state of an application is captured in an event object, and that these event objects are themselves stored in the sequence they were applied for the same lifetime as the application state itself.

Quindi, quando hai bisogno di ripristinare lo stato del tuo sistema in un dato momento, rigiochi lo stato memorizzato , non i gestori di eventi, fino a quel momento.

Detto questo, se lavori solo con dati di stato, non ci dovrebbero essere effetti sul sistema esterno. A meno che tu non abbia trigger o osservatori nel tuo archivio eventi, nel qual caso dovresti disabilitarli per la durata del ripristino. Dato che dici di non avere alcun controllo sul sistema esterno, non ci dovrebbero essere tentativi di ripristinare il suo stato usando l'API esposta poiché non sai quali effetti collaterali potrebbero avere nel loro sistema. Se il ripristino mette il sistema in uno stato intermedio (ad esempio a causa di operazioni non riuscite nel sistema esterno), questo non dovrebbe rientrare nelle responsabilità di una riproduzione di eventi.

    
risposta data 10.06.2017 - 12:48
fonte
2

But, what if one of the events should cause an external system not in your control to "ship an item" to the customer if you just replay the events the item would be shipped twice.

Per scegliere un esempio specifico, consideriamo come potrebbe funzionare un approccio "almeno una volta" agli effetti collaterali.

State currentState = State.InitialState
for(Event e : events) {
    currentState = currentState.apply(e)
}
for(SideEffect s : currentState.querySideEffects()) {
    performSideEffect(s)

Quindi il modello di dominio tiene traccia di ciò che deve essere fatto; ma lascia il fare effettivo all'applicazione

Nel contesto dell'esecuzione di un comando, l'idea di base è la stessa. Gli effetti collaterali effettivi si verificano fuori della transazione che aggiorna il modello.

Quindi l'unit test per il tuo modello potrebbe sembrare qualcosa di simile

{
    // Given
    State currentState = State.InitialState

    // When
    Events events = List.of(OrderPlaced)

    // Then
    List.of(SendEmail) === currentState.applyAll(events).querySideEffects()
}

{
    // Given
    State currentState = State.InitialState

    // When
    Events events = List.of(OrderPlaced, EmailSent)

    // Then
    List.EMPTY === currentState.applyAll(events).querySideEffects()
}

I punti principali qui sono

  • L'aggiornamento del modello è privo di effetti collaterali; gli effetti collaterali effettivi si verificano al di fuori della transazione che aggiorna il modello.
  • Un evento che descrive il risultato dell'effetto collaterale deve tornare.
risposta data 10.06.2017 - 13:14
fonte

Leggi altre domande sui tag