DDD, Saga ed event-sourcing: un'Azione compensativa può essere semplicemente un'eliminazione nell'archivio eventi?

13

Mi rendo conto che la domanda di cui sopra probabilmente solleva un po 'di cosa, ma lascia che provi a spiegare:

Sto provando a racchiudere la mia testa su un paio di concetti correlati, in pratica il modello Saga ( link ) in combinazione con Event-sourcing (A DDD-concept: link )

Un buon post che lo avvolge: link

Sto arrivando alla domanda tra un minuto, ma penso di dover cercare di riassumere quello che ho capito prima (che potrebbe essere sbagliato, quindi per favore correggi se è così) perché questo potrebbe influire sul perché Sto facendo la domanda per cominciare:

  1. Il modello Saga è una sorta di broker che fornisce un'azione (utente finale, automatizzato, ecc., sostanzialmente qualsiasi cosa che cambierà i dati) divide l'azione in attività commerciali e invia ciascuna di queste attività come messaggi a un Message Bus che a sua volta lo invia alle rispettive radici aggregate di cui occuparsi.
  2. Queste radici aggregate possono funzionare completamente in modo autonomo (bella separazione di preoccupazioni, grande scalabilità, ecc.)
  3. Un'istanza di Saga non contiene alcuna logica di business, che è contenuta nelle radici aggregate alle quali invia attività. L'unica 'logica' contenuta nella Saga è la logica del 'processo' (spesso implementata come una Statemachine), che determina in base alle azioni ricevute (oltre agli eventi di follow-up) cosa fare (es .: quali attività inviare)
  4. I modelli Saga implementano una sorta di modello di transazione distribuita. I.e: quando una delle radici aggregate (che di nuovo funziona in modo autonomo, senza conoscere l'esistenza di ciascuno) non riesce, l'intera azione potrebbe dover essere annullata.
  5. Questo è implementato avendo tutte le radici aggregate, una volta completato il loro rapporto di attività sulla Saga. (In caso di esito positivo o errore)
  6. Nel caso in cui tutte le radici aggregate restituiscano un successo, lo statemachine interno se la Saga determina cosa fare dopo (o decide che è fatto)
  7. In caso di errore, la Saga emette su tutte le root aggregate che hanno preso parte all'ultima azione una cosiddetta Compensation Action, cioè un'azione per annullare l'ultima azione eseguita da ciascuna delle radici aggregate.
  8. Questo potrebbe semplicemente fare un "voto meno 1" se l'azione fosse "più 1 voto", ma potrebbe essere più complicato come ripristinare un blogpost alla sua versione precedente.
  9. Event-sourcing (vedi il blogpost che combina i due) mira a esternalizzare il salvataggio dei risultati di ciascuna delle attività che ciascuna delle radici aggregate intraprende in un archivio eventi centralizzato (i cambiamenti sono chiamati 'eventi' in questo contesto)
  10. Questo archivio eventi è la "versione singola della verità" e può essere utilizzato per riprodurre lo stato di tutte le entità semplicemente iterando gli eventi archiviati (essenzialmente come un registro eventi)
  11. Combinare i due (cioè: lasciare che le radici di aggregazione utilizzino Event-sourcing per esternalizzare il salvataggio delle modifiche prima di riferire alla Saga) offre molte buone possibilità, una delle quali riguarda la mia domanda ...

Ho sentito il bisogno di togliermelo dalla spalla, dal momento che è molto da capire in una volta. Dato questo contesto / mindset (di nuovo, si prega di correggere se sbagliato)

la domanda: quando una radice aggregata riceve un'azione compensativa e se tale radice aggregata ha esternalizzato le sue modifiche di stato utilizzando il sourcing di eventi, l'azione compensa in tutte le situazioni non sarebbe una cancellazione dell'ultimo evento nell'Event Store per quella determinata radice aggregata? (Supponendo che l'implementazione persiste consenta le eliminazioni)

Questo avrebbe molto senso per me (e sarebbe un altro grande vantaggio di questa combinazione), ma come ho detto potrei fare queste ipotesi sulla base di una comprensione errata / incompleta di questi concetti.

Spero che questo non sia stato troppo prolisso.

Grazie.

    
posta Geert-Jan 19.07.2012 - 02:23
fonte

4 risposte

7

Non dovresti eliminare gli eventi dal tuo negozio di eventi. Questi rappresentano qualcosa che è successo. Se succede qualcosa ora, dovresti saperlo anche tu, quindi aggiungi un evento che costringerà il tuo aggregato a tornare ad uno stato precedente. È un peccato cancellare le informazioni dal tuo database.

pensa all'esempio del carrello di greg young e degli articoli rimossi. Forse domani le informazioni sull'azione compensativa potrebbero essere di qualsiasi valore ..

Per quanto riguarda la saga, ogni cosa è corretta, per quanto mi conosco. Dovresti pensare alla saga come a una macchina statale. Lo fa solo.

È un comando che la saga sta emettendo per dire all'aggregato di fare qualcosa. Di questa azione ci sarà un evento. Questo evento potrebbe essere l'azione correttiva di cui hai bisogno, o potrebbe essere necessario denormalizzarlo in una vista in modo che alcuni utenti lo vedano per decidere cosa fare.

Dipende dalle tue regole aziendali. O c'è una soluzione semplice: la radice aggregata sa che in tal caso lo fai, o la scelta è troppo complessa per essere programmata (i costi di sviluppo sono troppo alti) e quindi potresti proporlo a qualche utente, che potrebbe scegliere tra diverse azioni. Tutto dipende dal contesto dell'azione compensatrice. Questa è pura regola aziendale. Cosa dovremmo fare in questo caso o in quel caso. Questo è qualcosa da chiedere al tuo esperto di dominio, e quindi scegliere con lui, se è meglio sviluppare una soluzione automatica o se la soluzione è chiedere all'utente Ronald R., perché è lui a rispondere di solito a questa domanda.

    
risposta data 19.07.2012 - 14:41
fonte
5

Per completezza ho pensato di includere uno snippet pertinente di Martin Fowler sui modi per ripristinare lo stato:

As well as events playing themselves forwards, it's also often useful for them to be able to reverse themselves.

Reversal is the most straightforward when the event is cast in the form of a difference. An example of this would be "add $10 to Martin's account" as opposed to "set Martin's account to $110". In the former case I can reverse by just subtracting $10, but in the latter case I don't have enough information to recreate the past value of the account.

If the input events don't follow the difference approach, then the event should ensure it stores everything needed for reversal during processing. You can do this by storing the previous values on any value that is changed, or by calculating and storing differences on the event.

Da: link

    
risposta data 19.07.2012 - 19:09
fonte
0

Concettualmente:

  • L'evento è qualcosa che è successo. Il passato non può essere cambiato.
  • Il comando è qualcosa da fare. Il comando potrebbe non accadere (può essere rifiutato).

Possiamo modificare il nostro stato futuro solo eseguendo un altro comando (Compensate Action) che dovrebbe comportare lo stato di modifica degli eventi dell'applicazione.

Per "confondere" la domanda, pensa a questa frase "cancella l'ultimo evento":

  • Cosa succede se l'ultimo evento non è quello che deve essere eliminato? Cosa accadrebbe se altri eventi accadessero dopo quello da cancellare? Anche questi eventi devono essere modificati (dato che il loro stato base sarebbe cambiato eliminando l'evento prima di loro).
  • Cosa succede se l'evento è stato inviato al sistema esterno? Potresti non avere accesso per correggere il suo stato se non l'invio di un altro evento.

In breve, non hai alcuna opzione per eliminare gli eventi all'interno del pattern CQRS.

Potresti ridurre il tuo Event Store creando uno stato di istantanea (basato su tutti gli eventi che portano a quello stato), ma questo aspetto fisico non ha nulla a che fare con il concetto di evento.

    
risposta data 06.04.2016 - 11:00
fonte
0

Geert-Jan, anch'io penso che l'azione di compensazione possa semplicemente cancellare gli eventi corrispondenti. Ha senso e mostra un altro vantaggio del modello di progettazione di Event Sourcing: implementazione più semplice del modello di progettazione di Transazione compensativa.

Alcuni dicono che l'eliminazione dell'evento viola i "principi" del sourcing di eventi o CQRS. Penso che sia una generalizzazione limitante. Penso che sia corretto cancellare un evento se è stato creato nell'ambito di una transazione globale che viene annullata. Considera lo pseudocodice:

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

Supponiamo che il tuo archivio eventi sia un database transazionale. Nello pseudocodice, è possibile immaginare la situazione in cui è stato inserito il primo evento, ma quando si è tentato di inserire il secondo evento è stata generata un'eccezione. Il comando rollback ripristinerebbe naturalmente l'inserimento del primo evento. È ragionevole?

Se è ragionevole per una transazione di database ACID (transazione con commit / rollback), perché non sarebbe ragionevole per una transazione di compensazione?

Quando si esegue la transazione Saga globale, le modifiche ai dati possono essere annullate (mediante compensazione). Non è necessario mantenere l'evento creato durante la transazione perché la transazione non è stata completata.

Ora, se la compensazione tenta di eliminare un evento e quell'evento non è il più recente evento su un oggetto, la cancellazione non dovrebbe verificarsi. Ma in generale, è improbabile che ciò accada, specialmente nelle soluzioni ad alta intensità di lettura.

    
risposta data 08.06.2016 - 00:23
fonte

Leggi altre domande sui tag