Axon Server + Invariants accross aggregates

I’m evaluating Axon, and whether it can replace our own in house event store.

One thing I’m curious about is how one would solve the email uniqueness problem in combination with Axon server. In our current implementation, the event store and special invariant tables with constraints are kept in the same database, so when creating a new user we will (in the same transaction) add a new email to the invariant table (which fails if the email address existed) and store a NewUserEvent.

With Axon we could conceivable do the same, but when using axon server these two actions (checking and storing the invariant + storing the event) would no longer be as atomic as we’d like as these tables would live on two different servers. How would this work in this case?

Welcome to the community John.
before giving you a long answer on how to implement this, let me ask you first what is you current technology stack. Are you using Axon Framework ? Which event store are you currently using ?

The question that you raised sounds like a “Set Based Validation Approach” to me : I leave you this blog post written by my fellow colleague Yvonne that maybe can clear out a bit your thoughts Set Based Consistency Validation.

Axon Server is a dedicated production-ready event sourcing platform, will for sure help out the team, bumping productivity and giving developers more time to focus on business logic implementation, instead of wrestling with architecture stack and debugging issues, and ops in managing easily the project needs. As a developer I enjoy this a lot on a daily basis.

Answers to your questions:

  1. Current stack is Java, Spring Boot, PostgreSQL, RabbitMQ.
  2. We’re not using Axon framework at this time.
  3. We’ve rolled our own event store, accepting events over RabbitMQ and dispatching them via Rabbit to subscribers.

The blog was helpful, this is indeed the problem I was referring to. However what I’m unclear on is how reliable this immediate consistency is provided by subscribing processors:

“Subscribing processors will create and maintain a projection immediately after an event has been applied and are immediately consistent.”

As events are stored in a separate store (Axon Server) it seems crucial to me that both the projection created by the subscribing processors and the events themselves are stored in the same transaction. However, the data involved lives on two separate servers requiring something like 2PC or an outbox pattern to keep them consistent. My question was how is Axon doing this?

My reason for evaluating Axon is primarily its ability to store and retrieve events, not so much the framework surrounding it (although that could be of interest), as I’m looking whether it be worthwhile replacing our custom event store with Axon’s.

The custom event store we’re using is working out well, but doesn’t support snapshots. It also has a different mechanism to ensure the correct order of events which is Postgres specific and doesn’t require tracking of gaps in the sequence (although I found the solution in GapAwareTrackingToken quite interesting).

Axon Server can indeed be used as an event store database only: you could connect your application using the https://github.com/AxonIQ/axonserver-connector-java.
You can store your events and write your own logic to make the operation of storing the events and updating your projection happening in the same transaction. You can even implement your own mechanism that will make your application read and support snapshots.

However, the concepts that you are describing are already present and implemented in the framework

  • “unit of work” coordinates action performed during the processing of messages, and guarantee that commits occurs after the unit of work is committed. You can read more here in the reference guide Unit of Work - Axon Reference Guide
  • using the framework capabilities you can perform retries in case of failure
  • snapshots are an out of the box feature, and framework will be in charge of rehydrate your aggregate based on the lastest snapshot available
  • event replay is another powerful feature that I could never ever personally do without it.

I don’t know status of your code, or how much advanced is your PoC, but I could for sure suggest to take a look at Axon Framework. You can also adopt a step-by-step approach, changing part of your application at iteration. Throught axon-amqp module you can connect to RabbitMQ and handle existing events that are produced by your application.

Learning Axon Framework is pretty straightforward and we share a good amount of code-saples among documentation, blog posts and podcast discussion. Or if you prefer we launched https://academy.axoniq.io/ as a new learning resource.

I’m also interested in John’s Question. What would happen, if the Axon Server commit succeeds but the commit of the subscribed event processing projection fails (or vice versa)?

The unit of work is not a replacement for a (here distributed) transaction. Are there any build-in or known solutions for that?

Without Axon Server it would be possible to add tables to the database that contains the event store, but it would be a pity to loose all specialized capabilities of Axon Server.