Design Question

I am using the current Axon 2.0-SNAPSHOT on a greenfield application. My question is about design using the new constructs in v2.0 vs what was available in 1.4.

I have an external service that my aggregate must communicate for validation. The service is accessed via AMQP calls. Using Greg Young’s advice I am keeping the external exits from my “domain bubble” to a minimum by wrapping these calls in domain specific service class.

Once such method is quite simply:

boolean isAccountActive(String accountCode);

What if the service is unavailable? I came into the aggregate from a command call. Axon 2 no longer has a non-domain event that can be applied from the aggregate. So do I need to pass along the EventBus so that I can fire a “system event”? Is there an exception adapter that could initiate a system event that could start a saga to continue trying to process this request?

As I write this I wonder if I should flip my domain sideways a bit. Maybe my aggregate could keep a date of the last time it validated the account. I could start a saga with the job to validate and when successful to fire a command of “SuccessfulAccountValidationCommand”.

Your insight would be greatly appreciated.

Hi Randy,

interesting case. The “what if the service is unavailable” is really one only you (or a domain expert near you) can answer. One thing you could do is fail the command. Alternatively, you can register (or apply) an Event notifying that an external validation could not be done. In the latter case, you’ll just assume an aggregate is valid unless you have a working service to prove otherwise. I’ve come across use cases where they have a similar approach with payment providers: if the payment provider is unavailable, you get the product (an upgrade of your seat in an aircraft) for free. Makes you want to try to… never mind.

Your idea about a Saga sounds very reasonable, if you need validation every “now and then”. If validation needs to occur for specific commands, the Saga won’t really help. But performance wise, it is generally better to try to get calls to external systems out of your command handling logic. If that isn’t possible, your own domain-specific abstraction layers is a “must”.

About applying the events, why would you want to dispatch an application event from an Aggregate? If you apply a regular domain event, you’ll get the Event in your event store, giving you a trace of what happened. But I can’t consult your domain expert right now, so let’s assume it needs to be an application event. In Axon 2, you can register Events for dispatch in a unit of work. Just add a parameter of type UnitOfWork to your @CommandHandler method (or call CurrentUnitOfWork.get). On the UoW, call registerEvent(). This will dispatch an event, without applying it to the aggregate. The order of events in apply() and uow.register() is the order in which the events will be dispatched on the Event Bus. But again, make sure you really don’t need it as a Domain Event.

A little background: Axon 2 doesn’t make an explicit difference between Domain Events and any other type of event any more. The only difference between Domain Event and the others, is that a DomainEvent(Message) keeps a reference (by identifier) to the aggregate it was generated by, and a sequence number (i.e. the aggregate’s version).

Hope this helps.
Cheers,

Allard

Hi Allard,

Thank you very much for all of that information. Especially with regards to passing the UoW to the command.

I have progressed further with this and I am using a saga to validate and to issue commands to the aggregate on success or failure. You’re right in that they are domain events and that makes perfect sense to me.

I updated my existing unit tests to include the validation and to look for the expected behaviour should the validation fail. My AnnotatedSagaTestFixture has a .expectDispatchedCommandsEqualTo with the expected command for an invalid entry. The test method requires that my command class has implemented the equals contract. Is there a framework reason why this method behaviour is not like FixtureConfiguration.expectEvents for events?

Randy

Hi Randy,

in the fixtures “Axon 2 style”, there are two methods for validating commands (and events as well): …EqualTo and …Matching. The first relies on a properly working equals method. The latter allows you to define the expected command using a Hamcrest matcher. Note that the matcher is given a “List of CommandMessage”. There is a number of matchers available through static factory methods on the Matchers class that help you break down the list and mach individual items.

There is some information about this in the reference guide as well:
http://www.axonframework.org/docs/2.0/testing.html#d4e1859

Cheers,

Allard