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.