I came across two quotes by Allard (see below) which seem contradictory to me.
I could run some code to test possibilities, but decided to do it later and clarify it more on conceptual level first.
Just to make it clear, by “aggregate instance” I mean loaded aggregate. My understanding is that, because aggregates have identity, they are supposed to be “singletons” suggesting only single live instance of it to be loaded at any time on any node within distributed system.
“Command instance”, on the other hand, is a value object (or even has no concept in DDD at all and considered as CQRS-type implementation detail only). What I mean is that it can actually be represented by its multiple clones of itself across all JVMs participating in the system (with special measures to avoid duplicate processing if such command is not idempotent).
Quote 1: “It is possible to do as many actions on as many aggregates as you like. But if scalability is a big concern, it’s good practice to have a 1 to 1 relation between command and aggregate. The reason for this is that the command handler must load all aggregates into the same machine. With scalability, that means you need to prevent other machines from changing those aggregates in the meantime… the problems are obvious. […] So if you have a “composite command” (one that executes on multiple aggregates), there is really no limitation to do so. […] So Axon won’t be limiting you there…”
Quote 2: “Note that for each command type, there may only be one handler! This restriction counts for all handlers registered to the same command bus.”
The quote is from section “3.3.3. Annotation based handlers” in the reference:
At glance these quotes conflict one with another.
I can try to disambiguate one case: the 2d quote is obviously refers to command type and handler type (and not possibly multiple instances of them). So, at this point it means that there could be multiple instances of the same type of command which are handled by multiple instances of the same type of handlers.
However, annotation @TargetAggregateIdentifier results in single aggregate id (not multiple) and, therefore, single handler destination. It suggests that each individual command instance can only be processed by specific single handler instance. Maybe it is only applicable when handler is an aggregate and not an arbitrary class with methods annotated as @CommandHandler.
Assuming C is command type, H is non-aggregate handler type, and A is aggregate handler type, there could be multiple scenarios (or modification/mixture of them) imagined how instances (numbered below) may interact:
Scenario 1: single command instance is processed by single aggregate instance and many other non-aggregate handler instances.
C1 --|-> H2
Scenario 2: single command instance is processed by any number of handler instances regardless whether they are aggregates or not.
C1 --|-> H2
Scenario 3: each command instance is only processed by single handler instance (aggregate or non-aggregate).
C1 ----> H1
C2 ----> H2
C3 ----> H3
C4 ----> A1
C5 ----> A2
C6 ----> A3
If @TargetAggregateIdentifier directs command to only specific aggregate instance (with specific id), how can there be multiple aggregate handler instances processing it (as described in quote 1)? Is it because of non-aggregate handler instances?
So, what scenarios are possible?
Are non-aggregate handler instances even normal/common cases in practice? Or is it usually applies to only some special cases like Saga pattern?