Axon for EventSourcing only (no Commands/Queries)?

Hi,
I am using a modular monolith approach with JPMS to separate my reads and writes so I don’t feel a need for local command and query gateways.
My monolith will answer REST calls that are already behind an API gateway, so it will be load-balanced, etc…
So this is my rationale to look for a way to go straight from a REST Controller to an aggregate without the command pattern. (and the same for queries)

It is not documented, not discussed, and the code says it won’t be straightforward…
Can any IQ member confirm it is not supported and I must use at least a synchronous local commandBus (and the same for queries)?

It is supported, in the sense that you can use a few components from the framework to make it work. Typically, and easier to setup is an Aggregate that works with command messages. So some of that you need to do yourself. You can also just fire a command from the Rest endpoint?

The query part is very easy to leave out, by going directly to the projection.

1 Like

Thank you for your quick answer.

I was looking for a controller calling a business layer, that will be a @Transactional, handling Axon’s unit of work, handling external services, calling the aggregate repository, and delegating only business logic to the aggregate.
But I do not see a way to use EventSourcingRepositories without CommandMessages as the repository needs a unit of work, that needs a CommandMessage (or DeadQueueLetter).

About the why:
RestController could fire a command to a gateway that dispatchs in a local-only commandBus that will forward the message on always the same handler, in the same process (JVM).
We are load-balanced by API Gateways, so I guess we will never need a distributed commandBus.
Being in a single process a direct Java call is more efficient than dispatching in a command gateway.

PS: There is still value in firing a command from the Controller as isolating business modelization from external / I/O modelizations (API, …).

I’m not 100% sure, but won’t using the SimpleCommandBus solve the problem, as it will create the unit of work for you, still in the same thread?

1 Like

If you really wouldn’t want to use Axon’s CommandBus and QueryBus with their respective message, you are indeed inclined to construct and manage the UnitOfWork yourself. This would also mean you are inclined to attach Axon Framework’s TransactionManager to the UnitOfWork you construct yourself to keep the transactionality of the Aggregate-Repository.

However, with that in place, you could invoke the Repository from within your controller if you like.

Granted, the above is all boilerplate Axon Framework resolves for you, if you just dispatch a command message.

Although I agree JPMS helps for modularization, it does not streamline the communication between your modules directly. Using Commands, Events, and Queries for this (thus, CQRS) is just an additional helper to clarify the communication.
Furthermore, by using message buses, you are free to have these modules in a single unit now and break them apart in the future. All you would have to do is change the message bus configuration from a local to a distributed version in that case.

Let me dive into another point you’re sharing, @Nicolas_Fedou:

The SimpleCommandBus is nothing more than a direct invocation on the same thread. The bus just abstracts the handler away from you, making the messages your API instead of a set of interfaces.

To stick to the protection of your consistency boundary in a distributed environment, you would want to ensure operations dedicated to a given model are routed to the same instance consistently. Doing so eliminates the need for a distributed transaction or dealing with the exception of a concurrency exception. In that frame of thought, you would require either (1) Axon Server or (2) a DistributedCommandBus using
Axon Framework’s Spring Cloud or JGroups extension

Even when you are taking this route, Axon Framework will ensure that if the message can be routed locally, it will be acted upon locally. In both the case of Axon Server and the DistributedCommandBus, there is indeed an Executor that constructs a new thread for the actual invocation. I think a small price to pay not to have to deal with distributed transactions.

Conclusion

Long story short, you could go without using Axon Frameworks message buses. However, I think it will make things a lot easier for you, without coming with the drawbacks you’re assuming. I’ll be looking forward to additional drawbacks you may have, @Nicolas_Fedou!

1 Like

Thanks for the detailed answer.

Axon’s natural use case is to have a Message. The alternative where we have to build a UnitOfWork and a transaction manager goes deep into an evolving framework and reduces the ability to have support.
I will use a SimpleCommandBus, it will force a command pattern and lower the cost of maintenance.

Thank you, Gerald and Steven for your insights.

2 Likes

Happy to help, @Nicolas_Fedou! Be sure to come back with other questions if you have any :slight_smile: