Why I regret not embracing Axon Server sooner
I have been a Solution Architect at AxonIQ for over a year. Before that, I was a software developer, bringing an Axon Framework application into production with a regular Oracle database as an event store.
Over the past year, I developed several Axon Framework applications with Axon Server, and it makes your life so much easier. It’s not just an event store but also a distributed message bus that automatically routes all your messages! Looking back on my time before AxonIQ, I wish I had made the jump sooner.
Intermission: Isn’t promoting Axon Server your job?
It depends on how you look at it. I work at AxonIQ, and my job is to help customers achieve the best possible solution with Axon Framework, event sourcing, and CQRS. Besides helping customers, I take customer wishes and pain points back to our product teams and even develop Axon Framework and our other tooling of AxonIQ, such as Inspector Axon.
Everything I tell you here is genuine and from personal experience developing applications with Axon Server and without. There’s a lot of good, and some things to keep in mind, so I will keep a balanced view throughout this article.
Optimized for events
Regular databases are optimized for storing relational data or documents. Axon Server, however, is optimized for storing and retrieving events as necessary for event sourcing and event streaming to work. It supports retrieving events from both the entire stream or for only a single aggregate identifier. Due to the way indices work and the stores’ append-only nature, it’s very fast even when the event store grows to billions of events. That can unfortunately not be said for other databases.
Regular databases have the problem that other instances of your application will not be notified when events are added to the table. This means that they will have to continuously poll the database. Not only can this cause delays, but it can also cause headaches for your Database Administrator (much as I regularly annoyed mine).
Axon Server pushes newly published events immediately to connected instances. This means the latency from publishing to handling in the event processor is in the single-digit milliseconds for all connected applications. There are no more delays while waiting for the next database poll!
There are downsides to such an optimized, append-only event store, though. You can never change the events inside of it. Once you commit them, they are there. Forever. This sounds scary, but there are ways to cope with it. Axon Framework contains upcasters, which can change an event before they are deserialized. Is an event broken? Write an upcaster, deploy the application, and it’s fixed! Conversely, you no longer need to perform manual SQL statements on your production database.
Resilience for concurrency
When I used Axon Framework on a highly-available application, I often got concurrency exceptions. This exception occurs when multiple application instances write an event with the same index for the same aggregate. Only one can win since they are deciding based on the same state. It’s a safety measure that prevents wrong decisions, and you should be happy it’s there!
However, despite being there for safety, it’s annoying for you. You must retry your command or report the error to your user, even though it can be prevented by routing commands for the same aggregate to the same application instance. This is what Axon Server does and is something we call consistent routing.
Not only does it prevent problems with concurrency, but it will also ensure you can use aggregate caching as efficiently as possible. Very useful!
Much more than an Event Store
Axon Server does not only broadcast events, but it also is a location-transparent message router for commands and queries. This bus is much more useful than you’d initially think.
Back at my previous job, I had two ways to communicate with others: HTTP and JMS. When using HTTP you need to know four things; which microservice is hosting the endpoint, which address belongs to that microservice, which endpoint of the microservice it is, and what the required format is. This all becomes part of its API and cannot easily be changed.
For JMS, you need to know the queue name. If you expect a response, however, you cannot wait for it. The API is both the queue name and the message format. As you can probably guess, we used HTTP for synchronous and JMS for asynchronous communication.
It can be so much easier. Axon Server supports events, queries, and commands as messages. Events are broadcasted to all listeners asynchronously, queries are load balanced to the handlers and await a result, and commands target a single handler with consistent routing.
Axon Server routes all messages using their name or payload type. Since every component declares to Axon Server what messages it can handle, it can route any message to any instance. It’s like a microservice matchmaker, setting up dispatchers and handlers with each other.
Integration is effortless because of this, you just send the right message (most probably from a published API library) to Axon Server, and you don’t need to know anything about infrastructure. You do not need an HTTP address or a Kafka topic with partitioning. This also means you can move handling components between microservices without any dependent services changing anything.
There’s one specific hero message that I would like to highlight. It’s the subscription query!
You send a query and request an initial result and any updates that follow for the duration of the query. Your stream gets pushed any update from the remote component, allowing you to create a stream to your frontend. This is what we built Inspector Axon on, and it works wonders for reactive UI frameworks.
Development support saves precious time
Last but not least, many customers don’t just buy Axon Server for Axon Server. They buy it for our outstanding support and help on Axon projects. Each of our customers gets a dedicated Slack channel with us and can ask anything about software architecture, Axon Framework tuning, or anything else within reason. They get very quick and helpful replies, unsticking them from their problems or questions. That help would’ve been very helpful while I was at it! This can save a lot of time on development efforts.
I wish I had tried out Axon Server at my previous job and introduced it. I believe that the landscape would have been in a much better shape if I did that. With the three types of messages, their routing by Axon Server, and the location transparency of all the messages, the code would contain much more business and much less infrastructure.
If you’d like to give Axon Server a shot after this blog, it’s free to download. It will simplify your microservice communication a ton.