Records do not accumulate forever. Each carries a TTL, and a scheduler removes the expired ones.
idempotency:
default-ttl: PT24H
purge:
enabled: true # Default: true
cron: "0 0 * * * *" # Default: hourly@EnableScheduling is required
purge.enabled needs @EnableScheduling on your application to do anything. The starter
warns at startup if it is on without it, rather than quietly never purging.
@SpringBootApplication
@EnableScheduling
class Application { }TTL is a retention control
default-ttl decides two things at once, and they pull in opposite directions.
How long a duplicate can still replay. A client that retries after the TTL has elapsed gets a fresh execution, because the record is gone. The TTL therefore has to outlast your clients’ retry behaviour - including a client that retries the next morning after an overnight outage.
How long the data is kept. The store holds whatever the adapter hands it, which over HTTP means full response bodies. Keeping TTLs short limits retention, which is the main lever you have over the exposure described in security.
The default of 24 hours is a reasonable middle. Set it per method on
@Idempotent where a particular endpoint needs longer
replayability or holds data that should not linger.
What gets purged, and when
A completed record is purged once its TTL elapses.
An abandoned IN_PROGRESS record is purged only once its TTL has elapsed and its lease
has expired too. Both conditions are required so a legitimately long-running action, whose
heartbeat is still extending its lease, is never purged
out from under itself.
Tuning the cron
The default is hourly. Purging more often keeps the table smaller and each run cheaper; purging less often is lighter on the database. The Redis provider’s purge is a bounded SCAN, so a single run does not block the server.
If you run several instances, they all purge. The operation is safe to run concurrently - it removes rows that have already expired - so no coordination is needed.