Choosing an Approach
Two decisions, in order. First, where the process lives. Then, if it keeps state, how that state is held. The second question applies to a whole process class and to an individual slice alike.
Workflows come first because they are the recommended answer wherever they are available, and that recommendation does not depend on the process. They are the most advanced of the options and the easiest to write. The gap widens as the process grows: adding a step is adding a line, where every other approach makes it a new handler, a new piece of state, and a new correlation to get right.
The approaches after them are ordered by how little they ask of you, not by elegance. Each is a complete answer needing nothing beyond Axon Framework, and the same contract test in the example module holds for all of them.
Where the process lives
| Approach | Good for | Costs |
|---|---|---|
Any process, and the recommended answer wherever it is available. The flow is written as a flow, no state is yours to keep, and extending it later is a line rather than a new handler. Many steps, branching, compensation and waiting are where the difference is largest, but there is no size below which something else is preferable. |
A dependency and a licence, and it is a preview rather than a production release. |
|
Vertical Slice Architecture and Event Modelling. The best transactional profile, since each slice does exactly one thing. Each slice also picks its own answer to the state question below. |
No single place describes the process any more. Only an event model shows it whole. |
|
One process class |
Processes people reason about as a unit, and teams not organized around slices. The flow is legible in one file. |
It couples the reactions together, so a change for one can affect another. |
If you are on Axoniq Framework and can accept a preview, write the process as a workflow and stop reading here. Everything after this point is what to do when that is not available to you.
How state is held
These are not alternatives to the slice or the class. They are what goes inside one, and a slice-based process may use a different one per slice.
The column that usually decides is the last, and it is the event store context that counts, not the bounded context. A process coordinating entities whose events all live in one context can use any of the three, however many bounded contexts those entities belong to. A process waiting on another Axon Server context, another team’s service or a payment provider cannot rebuild what it never receives, and is down to two.
| Approach | Good for | Costs | Works across |
|---|---|---|---|
The first thing to try. Ordinary, queryable state, and it does not care where the events it reacts to come from. |
Two things happen per step, a row written and a command sent, and the write has to roll back when the command fails. |
Any number of contexts |
|
Processes whose state is already implied by events in your own context. Stores nothing, so nothing can fall out of step. |
Invisible: a step that produces no event leaves no trace. One extra read per event. |
One context only, since the entity is sourced from one |
|
Long or regulated processes wanting an audit trail of the process itself, and integration with systems whose events are not yours. |
The most machinery of the three: its own events, and either an extra command or an append from an event handler. |
Any number of contexts, because it sources only its own |
If you want the smallest step and the fewest new ideas, start with state in a repository.
|
Try removing the need for state first
Before choosing where to keep process state, check whether you need any. A common reason a process keeps state at all is to remember an identifier it could have computed. If the process can derive one side’s correlation value from the other’s, both directions are free: outbound it computes the value the receiver expects, inbound it reads that same value straight off the event. Several of the approaches above become dramatically simpler, and one of them becomes possible at all, because of that one choice. |