Saga Retention
Completed sagas are kept as tombstones so a late or duplicate event is skipped idempotently rather than resurrecting a finished saga. Retention removes those tombstones once they are old enough to no longer serve that purpose.
Retention is off by default: it is active once a max-age is set, for every saga type or for one.
There is no default max-age.
It deletes completed sagas whose completion is older than that age, on a schedule.
Enabling retention
spring:
ddd:
saga:
retention:
max-age: 30d # delete completed sagas older than 30 days
With only a max-age, retention runs every hour.
A short max-age (for example 30s) approximates delete-on-completion while still keeping the idempotency tombstone for the grace window.
|
Scheduling
Choose either a fixed delay or a cron expression — setting both is rejected at startup.
| Property | Behaviour |
|---|---|
|
Whether this instance runs retention. |
|
Fixed delay between runs (for example |
|
Spring 6-field cron expression (for example |
|
How many completed sagas one delete statement removes; a run deletes chunk by chunk until a chunk is not full. From 1 to 1000, |
Cron is the better fit for a maintenance job — it lets you target an off-peak window instead of an arbitrary wall-clock time.
spring:
ddd:
saga:
retention:
max-age: 30d
schedule:
cron: "0 0 3 * * *" # 03:00 every day
Per-saga max age
A saga type can keep its completed sagas longer or shorter than the global max-age.
Name the type under spring.ddd.sagas, keyed by its @Saga(type) id; a type without an entry uses the global max-age.
Retention is active as soon as any type has a max-age, so the global one may be left out and only the types that need retention set it.
spring:
ddd:
saga:
retention:
max-age: 30d
sagas:
overdraft-saga:
retention:
max-age: 7d # keep overdraft sagas for 7 days
transfer-saga:
retention:
max-age: 365d # keep transfer sagas for a year
A type cannot be exempted from a global max-age, only given a longer one.
A key under spring.ddd.sagas that names no saga type fails the startup, and a saga type with a dot in its id is written in brackets, "[payment.saga]".
The same entry overrides the consumer settings of that type; see Event delivery.
How retention runs
Every instance whose schedule.enabled is on runs retention on the schedule; retention takes no lease.
Two instances can delete at the same time without harm: each completed saga is deleted once, and a run that finds nothing left deletes nothing.
Set schedule.enabled: false to limit retention to the instances you choose.
An application that declares its own SagaStore and sets a max-age fails the startup unless it also supplies its own SagaRetentionStore.
For the full spring.ddd.saga.retention property table, see Configuration properties.
Related pages
-
Overview — concept, delivery model, lifecycle, starters.
-
Writing a saga —
@Saga,@SagaEventHandler, handler parameters, worked example. -
Storage & tables —
@SagaTable, JSON persistence, when a saga ended, schema creation. -
Deadlines & timeouts — scheduling and cancelling deadlines from within a handler.
-
Event delivery — the topics a saga reads, one consumer per saga type, delivery guarantees.