Correctly representing singleton settings aggregates and resulting Axon tests failing

Greetings,

We have a set of discrete, long lived clients. Each client (unfortunately) has an identifier that is just simply their name as a String, like “ABCorg”. It is by this name that the consumers of our API know how to communicate which client to us.

Originally, we created singleton aggregates, one for each client, to keep track of their payment settings (and also perform tasks like queueing). The identifier for these aggregates were just their name, ie “ABCorg”. As each payment aggregate came due, it would have to transact the settings aggregate for the client that it was ascribed to so as to know the correct settings to apply.

Now, I am having to create more settings for each of the clients, but these new communication settings don’t relate to payments. I wanted to create separate singleton aggregates for these new settings, but then realized that the AggregateIdentifier would be the same (ie, “ABCorg”), and I cant have a PaymentSettingsAggregate with an id of “ABCorg”, and a CommunicationsSettingsAggregate with an id of “ABCorg”.

Are there any recommendations for how to handle this situation in DDD/CQRS/Axon?

My current solution has been to group the commands by functionality (ie all the payment settings commands in one package, the communication settings commands in another), and then put the @TargetAggregateIdentifier on a method in the command that will generate the ID. Then I take the client name, and append a suffix that identifies the settings aggregate it belongs to, ie

ABCorg_PaymentSettingsAggregate would be one ID and ABCorg_CommunicationSettingsAggregate would be another ID.

That way, the consumers of the API can still just send “ABCorg” as an identifier, and I can append the rest of the ID on the fly to send it to the correct settings aggregate.

The annoyance of this approach is having to remember to idempotently append the suffix on request, and idempotently remove the suffix on response.

Also, if this is an acceptable approach, the other issues I have found is that the @TargetAggregateIdentifier method of the commands is not called in the tests when comparing the commands. As such, if the client name was supplied as “ABCorg” on command creation, then during the test it will compare “ABCorg” to “ABCorg_PaymentSettingsAggregate”, and the test will fail. Recommendations?

Never mind the tests failing, I just found in the documentation that you have to override equals for the .when() comparison to work.

This sounds like an excellent use case for a multi-entity aggregate, where each of the settings classes could be a property on the org aggregate. Axon will automatically route any commands targeting the org aggregate to the appropriate entity with a matching command handler.

Hi Joel,

Thank you much for the reply. I had thought about that approach. My worry going that direction was that what if, in the future, I need to have like 20 @AggregateMembers that represent the different possible settings for these discrete (lets say 10 in total) aggregates? Wouldn’t I create a throughput bottleneck, since so many different, and largely unrelated events would all have to transact the same 10 aggregates over and over? Moveover, what if there is a failure in one of the other AggregateMembers? I don’t want all the other settings aggregates to have to fail and/or take compensating action when one of the AggregateMembers suffers a failure. Thoughts?

Thanks again,

David

I think that all depends on what kinds of errors you are foreseeing. I can see use cases where it may be necessary to alert related entities when there is an accepted failure in business logic, or even an unhandled programming exception. As for performance, you could use snapshotted aggregates instead of event-sourced aggregates so that loading the aggregate for processing of any entity is an O(1) operation. I’d optimize your code for logic and then after the fact optimize for performance.