Aggregates Existence Validation

Hi,

I think this question has been risen multiple times but it is still unclear for me how to handle following case.
I have 3 aggregate types: A, B and C
In order to create an instance of aggregate A by a command CreateAggregateA(aggregateBId, aggregateCId)
I need to validate that instances of Aggregates B and C with ids aggregateBId and aggregateCId do exists.
In case if some aggregate doesn’t exist I need to throw a domain error.

What would be a best way to do that in Axon?

I have though about following solutions:

  1. Use External Command Handler.
    Inject Aggregate Repository there, load aggregate by ID and in case of AggregateDoesntExist prevent aggregate creation by throwing a Domain Error.

  2. Use Saga and ask Aggregate B and C for Aggregate A creation approval.

  • send command to create Aggregate A.

  • start saga on Aggregate A creation

  • send 2 commands to Aggregates B and C and ask them with a command like: RequestAggregateACreation() (it is going be two different classes for Aggregates B and C)

  • wait for command responses and catch AggregateDoesntExist, then throw Domain Error

  • listen to events from Aggregate B and C with response like: AggregateACreationApproved() (also two different classes for Aggregate B and C)

  • when both approval received, send ConfirmAggregateACreation() command and as result an AggregateACreationConfirmed() event will be emitted.

  1. Use some Registry Projection for aggregates B and C, inject it as Resource into AggregateACreationSaga and query something like DoesAggregatesBAndCExist?
    And then wait for query response (which will block saga).

  2. Same as 3-rd point, but instead querying, use External CommandHandler and emit events like in point 2. Then saga can listen to them asynchronously.

  3. Use Long Lived Saga (forever) to act as Registry from 3rd point. – that’s not make too much sense.

What would be better approach?

+1 And one more question. How can I get sync response?

Hi Sergey, about “getting sync response” I think you want to send command and wait for all sagas and projections be updated which goes against eventual consistency paradigm. But it is still possible to do that. Just use Query Bus subscriptions and wait for certain query subscription on Application side. Subscription mechanism is documented well enough in official axon document.

About my original question. We decided to move towards validation on Command Interceptor using read model. Because as I said aggregate A only cares about Aggregate B and C ids. And because of eventual concictency that validation is also has to be soft (in case of creating Aggregates A,B,C at the same time). So eventual concistency and validation on fly is “a bit” mutually exclusive.

But Axon is limiting developers in some cases, so I was wondering what is the best way to do that in Axon. So I hope some one from Axon Team can share their thoughts about that.

Cheers,
Anton

I’m more interested in sync error response when the aggregate in saga cannot be created. I think the query model doesn’t suit here.

Hi Anton, Sergey,

Let me first answer Sergey, as I think that’s shorter:

Sergey’s question

What Anton points out to you is completely correct. You are dealing with an eventual consistent system, so typically it’s desirable to embrace that; it just simplifies your live a lot.

If you need to have a synchronous response from a Query Model, Anton’s further suggestion also fits well.
Introduce a Subscription Query which subscribes to the expected result of handling the Command you’re going to publish there after.
This GitHub repository by Frans van Buul shows this solution nicely.

If it’s a synchronous response, or error response, only from handling your Command, you should start to leverage the CompletableFuture which is returned to you when dispatching commands through the Command Gateway. The CompletableFuture will either be handled successfully, which typically doesn’t contain a result, or exceptionally, which will contain the exception you are apparently looking for.

And now, for your question Anton:

Anton’s question
You might have already run into this situation description, but what you’ve run into is the requirement for set validation.
I think this post by Daniel Whittaker explains it quite nicely, also with some options you can go for.

The set-validation issue when creating a given Aggregate which might already exist is something we do have on our backlog.
The situation you’re describing goes a step further however.

You not only want to check whether Aggregate A exists, but also whether B and C exists.
If the framework would support this check through a given Aggregate Repository, it would mean we’d expose the other Aggregate types, and their Repositories, to one another.

I do not feel that to be the right path to take to be honest.
Given the nature of your scenario, I think the path you’ve taken is valid.

By the way, did you use a CommandHandlerInterceptor or CommandDispatchInterceptor?

My gut feel would say it should be a dispatch interceptor, as you’re validating over more than just that one Aggregate.
Thus, it is prior to the boundary of that Aggregate, on the dispatch operation.

You have also asked the following:

Also I’m wondering why saga cant be started by a command? or Aggregates listen to events?

  1. A Saga started by a command is something we have been debating and might very well be something we’ll introduce in the future.
  2. An Aggregate as set up as the Command Model in your application, thus dealing with Commands to make the business logic decisions of your domain. Expanding it by being able to deal with other Aggregates or other Bounded Contexts is exactly what the Saga’s task (or if the transaction is straightforward, a regular Event Handling Component) is within such a system. An Aggregates message handling capabilities are thus narrowed down to handling Commands targeted to it and the Events it has published itself (for Event Sourcing for example).

Lastly, I want to talk about the following you have shared with us:

But Axon is limiting developers in some cases, so I was wondering what is the best way to do that in Axon.
Would you mind specifying in which ways you feel Axon Framework/Server is limiting you in your operations?
We very much strive to make Axon as user friendly a product as possible, with the highest wish on letting the user focus on it’s business functionality and thinking about the non-functional requirements later.
So, if you’d be able to be more specific about what you feel is missing, it would be very welcome if you’d contribute with providing issues on GitHub describing some of the envisioned solutions for the ‘limiting factors in Axon’.

Hope this helps you both out, Anton and Sergey!

Cheer,
Steven