Sto lavorando a una piccola applicazione di esempio per apprendere i concetti di CQRS e di sourcing degli eventi. Ho un Basketaggregato e un Productaggregato che dovrebbero funzionare in modo indipendente.
Ecco alcuni pseudo codici per mostrare l'implementazione
Basket { BasketId; OrderLines; Address; }
// basket events
BasketCreated { BasketId; }
ItemAdded { BasketId; ProductId; Quantity }
AddItemSucceeded { BasketId; ProductId; Quantity }
AddItemRevoked { BasketId; ProductId; Quantity }
ItemRemoved { BasketId; ProductId; Quantity }
CheckedOut { BasketId; Address }
Product { ProductId; Name; Price; }
// product events
ProductReserved { ProductId; Quantity }
ProductReservationFailed { ProductId; Quantity }
ProductReservationCancelled { ProductId; Quantity; }
I comandi sono abbastanza simili agli eventi, usando il nome imperativo e non il tempo passato.
In questo momento questi funzionano bene indipendentemente. Emetto un comando AddIteme crea un ItemAddedevento Basketsull'aggregato che fa quello che deve fare con lo stato del 'Basket'. Allo stesso modo, per prodotto il comando e gli eventi funzionano bene.
Vorrei ora combinare questo in un processo che sarebbe andato qualcosa del genere (in termini di comandi ed eventi che accadono):
Il gestore processi eseguirà le seguenti operazioni:
on BasketCreated: CreateShoppingProcess
on ItemAdded: ReserveProduct
on ProductReserved: SucceedAddingItem // does nothing, but needs to be there so that the basket knows it can check out
on ProductReservationFailed: RevokeAddItem
on RemoveItem: CancelProductReservation
on Checkout: CreateOrder // create an order and so on...
Le domande a cui non sono riuscito a trovare risposte definitive sono:
- Devo insistere sul gestore processi? Sembra di sì, ma non ne sono sicuro
- In tal caso, devo salvare gli eventi per il gestore processi. Tuttavia, gli eventi che sta ascoltando sono legati agli aggregati. Aggiungo l'id di processo a quelli? Ho eventi separati solo per il gestore processi? Come fare questo e mantenere il più asciutto possibile
- Come faccio a sapere a che basket
ProductReservedsono destinati gli eventi? Va bene avere un ancheBasketIdsu quelli o sono informazioni che perdono? - Come posso mantenere una relazione tra eventi, come faccio a sapere quale
ItemAddedprodotto ha prodotto qualeProductReservedevento? Passo unEventId? Sembra strano ... - Dovrei implementare
Basketcome gestore dei processi anziché un semplice aggregato?
Dopo alcune ulteriori ricerche sono arrivato a questo: una saga è qualcosa che mantiene i suoi eventi e ascolta gli eventi dall'esterno. Fondamentalmente, è un aggregato che può anche reagire agli eventi che accadono al di fuori del suo piccolo mondo.
Un Process Manager lavora con gli eventi dall'esterno e invia comandi. La sua storia può essere ricostruita dagli eventi accaduti sugli aggregati che condividono un identificatore comune come una correlazioneId.