Saga Migration
Axon Framework 5 has no Saga construct. Replace it with existing core framework building blocks.
The familiar @Saga stereotype and related APIs will not be ported to the Axon Framework 5 core.
The same applies to the DeadlineManager and related APIs.
A legacy layer allows migrating running sagas and deadlines.
For new processes, Axon Framework 5 provides several ways to implement them with the existing framework building blocks. The Sagas and Process Managers guide describes them in detail.
For sagas that are already running (considering business processes running for months), rewriting is not an option.
That case is served by the axon-legacy module, described in Running existing sagas on Axon Framework 5.
|
For saga migration you need to consider two scenarios: Writing new processes: Pick an approach from the Sagas and Process Managers guide and write it today. Migrating running sagas: Use the Axon Framework 4 compatible APIs of the |
Running existing sagas on Axon Framework 5
The axon-legacy module allows migrating to Axon Framework 5 while saga instances started on Axon Framework 4 are still running.
Business processes covered by sagas can span weeks or months.
axon-legacy lets running saga instances continue while new instances start on an Axon Framework 5 native implementation of the business process.
The axon-legacy module brings forward the following Axon Framework 4 saga and deadline infrastructure, adapted to the Axon Framework 5 APIs:
-
@Saga,@SagaEventHandler,@StartSaga,@EndSaga,SagaLifecycleand the association-value mechanism -
SagaStoreand its concrete implementations, to support existing saga stores -
DeadlineManagerand@DeadlineHandler
The legacy module supports existing saga classes as-is. Add axon-legacy as a dependency to your project.
|
The GitHub Issue #3728 tracks the saga side and GitHub Issue #3065 the deadline side. Until they are released, plan on the code-level migration below and on the drainage strategy in Migrating an application with running sagas. |
The axon-legacy module is a migration aid, not a supported way to write new processes. @StartSaga is deprecated.
The legacy module does not start new saga instances.
Existing instances receive their events and run to completion; new work goes to the Axon Framework 5 implementation written alongside it.
Mapping Axon Framework 4 saga concepts to Axon Framework 5
An Axon Framework 4 saga provides opinionated technical infrastructure to implement long-running business processes:
-
State is state-sourced: the saga instance is serialized into a
SagaStoreas an opaque blob -
Correlation requires association values, maintained with
SagaLifecycle.associateWith(…). -
Life cycle is framework-managed, through
@StartSagaand@EndSaga.
Axon Framework 5 provides several ways to implement long-running processes, described in Sagas and Process Managers. The following table maps Axon Framework 4 saga concepts to their Axon Framework 5 equivalents.
| Axon Framework 4 | Axon Framework 5 |
|---|---|
|
A |
|
|
|
|
|
The end of the workflow definition for a Workflow. For a plain |
|
|
|
a |
|
Your regular event store for a Workflow, a repository of your own, an event-sourced entity, or nothing. |
|
|
|
The dedicated Workflows Test infrastructure, or |
Replacing a saga with a workflow
The recommended replacement for sagas is Workflows: a process is written as a single method that reads top to bottom, using the regular event store for event-sourced persistence.
|
Workflows are an Axoniq Framework feature and require an Axoniq license to run in production. Workflows are currently available as a preview and can be tried out without a license. |
Saga concepts map onto Workflow concepts:
-
The association value becomes the workflow’s identifier and manual
associate(…)invocations when waiting on events. -
Each
@SagaEventHandlerbecomes a step. -
@EndSagabecomes the end of the workflow definition method. -
Deadlines are expressed as explicit wait or timeout on an event in the workflow.
Workflows differ from Axon Framework 4 sagas in how they hold state: they source it from dedicated workflow events in
the regular event store instead of a persistent SagaStore blob.
A running saga holding a serialized instance in a SagaStore cannot be handed to a workflow. It must drain as
described in Migrating an application with running sagas, whichever replacement you pick.
Migrating deadlines
Axon Framework 4 scheduled deadlines to defer reactions for sagas. Axon Framework 5 has no built-in deadline scheduling. Use other capabilities to get the same effect.
In Axon Framework 4, DeadlineManager schedules a deadline to trigger in the future; @DeadlineHandler handles the
trigger, typically by sending a command.
In Axon Framework 5, use a scheduling library of your choice: wire in the CommandGateway, and send the command
through the gateway when the scheduled task triggers.
An idempotent command handler ignores an action scheduled for a process that has already progressed.
See deadlines for details on deadlines for long-running processes in Axon Framework 5.
Choosing a replacement
Not every saga should become a workflow. Simple processes consisting of a limited set of independent reactions can use regular Axon Framework 5 event and command handlers. The guide compares the alternatives in detail:
-
State in a repository is the closest to how an Axon Framework 4 saga worked. Start here if you are porting an existing saga.
-
State from context events avoids persistent state in a repository. This is only possible if all involved contexts write to one event store and their events carry a tag you can select on.
-
State from process events suits integration with systems whose events are not yours, and gives an audit trail of the process.
-
Vertical slices break the process into independent reactions. This fits Vertical Slice Architecture and Event Modelling.
Migrating an application with running sagas
Whether or not you use the legacy module, migrate running saga instances by drainage: let saga instances created by Axon Framework 4 finish normally, while new process instances start on an Axon Framework 5 implementation.
Without the legacy module, drain old saga instances in an Axon Framework 4 deployment kept alive alongside the Axon Framework 5 application running the migrated process. The legacy module allows you to drain the old saga instances alongside the upgraded application in a single Axon Framework 5 application. Either way (using the legacy-module for drainage or not), new sagas must not be started from the Axon Framework 4 legacy code.
The main steps for migrating running sagas:
-
Stop starting new sagas. Remove the
@StartSagaannotation from the Axon Framework 4 saga. Existing instances keep receiving their events and run to completion; no new ones are created.@Saga public class PaymentSaga { // @StartSaga (1) @SagaEventHandler(associationProperty = "bikeId") public void on(BikeRequestedEvent event) { // ... } }1 Removing this annotation stops new instances from starting; existing instances can still advance and end. -
Keep the old saga running. With the legacy module, add the dependency and let the existing class continue against its existing saga store in the upgraded application. Without it, keep the Axon Framework 4 deployment alive to drain existing saga instances without creating new ones.
-
Implement the process in Axon Framework 5 using one of the approaches above, and let it handle the same trigger event.
-
Wait for the old instances to drain. Monitor the
SagaStorefor active instances and watch the count fall to zero. How long that takes depends on your longest-running process. -
Retire the Axon Framework 4 saga once there are no more active instances in the
SagaStore: remove the legacy saga code, theSagaStoretable, its deadline scheduler, and the legacy dependency.
Scheduled deadlines drain the same way: keep the Axon Framework 4 DeadlineManager, or the legacy module’s port of
it, online as long as saga instances still rely on it for deadlines.
Testing
A saga kept running on the legacy module keeps its existing tests.
Write new tests for the process migrated to Axon Framework 5 with AxonTestFixture: publish events that drive the
process and assert on the commands it sends.
The mapping below covers the common cases:
SagaTestFixture |
AxonTestFixture |
|---|---|
|
|
|
|
|
|
|
|
|
No equivalent. Assert on the observable outcome, or on your own state if the approach keeps any. |
|
No equivalent. Structure the timeout so it can be invoked directly; see deadlines. |
A working example
examples/saga-recipes in the
Axon Framework repository implements the bike-rental payment saga from an Axon Framework 4 sample application, using every approach described here.