So, I have following code:
public class CQRSQuestion { public static void main(String[] args) { //received command for algorithm run AlgorithmAR algorithmAR = new AlgorithmAR(111); algorithmAR.runAlgorithm(1,"2"); //after a while we receive another command to actually save algorithm results AlgorithmCachedResultAR cachedResultAR = loadCachedAlgResFromRepoById(123); AlgorithmAR algorithmAR1 = loadAlgorithARFromRepoById(111); algorithmAR1.applyCache(cachedResultAR); } class AlgorithmAR{ int algorithmId; AlgorithmPhase1Entity1 phase1; AlgorithmPhase2Entity2 phase2; void runAlgorithm(int param1, String param2){ phase1.doPhase1(param1, param2); } void applyCache(AlgorithmCachedResultAR cachedResultAR){ //since CQRS aggreagates are for writing only, can we use //something like cachedResultAR.getCache() here? } } class AlgorithmPhase1Entity1{ void doPhase1(int param1, String param2){ //do phase1 and construct Phase1Completed event Bus.publish(new Phase1Completed()); } @EventSourcingHandler void when(Phase1Completed event){ //set state of this object on intial publish and aggregate creation } } class AlgorithmPhase2Entity2{ @EventHandler //event handler is not run at aggregate creation from repo void when(Phase1Completed event){ //do phase2 and construct Phase2Completed event Bus.publish(new Phase2Completed()); } @EventSourcingHandler void when(Phase2Completed event){ //set state of this object on intial publish and aggregate creation } } class StatelessProcessManagerForAlg{ @ProcessManagerEventHandler void when(Phase1Completed event){ Bus.publish(new CachePhase1Command()); } @ProcessManagerEventHandler void when(Phase2Completed event){ Bus.publish(new CachePhase2Command()); } } class AlgorithmCachedResultAR{ int cachedResId; int algorithmId; void create(int param1, String param2, String param3){ //init aggreagate after phase 1 Bus.publish(new Phase1Cached()); } void create(String param3){ //update after phase 2 Bus.publish(new Phase2Cached()); } @EventSourcingHandler void when(Phase1Cached event){ //update internal state of this object } @EventSourcingHandler void when(Phase2Cached event){ //update internal state of this object } } } Here I have AlgorithmAR which is Aggregate root that executes some algorithm in 2 phases. After calling runAlgorithm on it, it calls AlgorithmPhase1Entity1 and method doPhase1. This entity then as a result of operation emits Phase1Completed event. This is published at same time to GUI (async) and to the event bus for other interested parties. Here, other interested party is AlgorithmPhase2Entity2 that will receive it in event handler when(Phase1Completed event) and after processing emit event Phase2Completed. Also, interested in this event is StatelessProcessManagerForAlg which is saga that emits command CachePhase1Command for creating other aggregate that stores cached results of algorithm. This command is routed to command handler, that as result creates AlgorithmCachedResultAR and calls method create on it. Params in create method are extracted from CachePhase1Command message.
All @EventSourcingHandler annotated methods execute on rehydration of aggregate from event store and on initial emit of events. @EventHandler annotations execute only on initial emit of events.
Now the question - since I need later to apply cached results of algorithm from AlgorithmCachedResultAR inside AlgorithmAR.applyCache(AlgorithmCachedResultAR cachedResultAR) method, should I do this - since by CQRS, aggregate root is only used for writing data. Here I would actually use AR for querying data from it. If I use read projection, I would have to create 1-1 copy of AlgorithmCachedResultAR which seems redundant here. Thanks!
Phase2Cached- this event name is probably a smell that your domain deals with technical stuff it shouldn't know about.