Everything is under the idempotency prefix. Transport-neutral settings sit at the top
level; those that only make sense over HTTP live under web, and those that only apply to a
JDBC store under jdbc, so an application that uses neither never has to read past the first
group.
YAML
idempotency:
default-ttl: PT24H # How long a completed record stays replayable. Default: 24h
default-lease: PT30S # How long an acquisition is protected. Default: 30s
default-wait: PT10S # How long a second caller blocks. PT0S to not block. Default: 10s
completion-mode: autonomous # autonomous | join-transaction, for @Idempotent methods. Default: autonomous
completion-failure-policy: log-and-return # log-and-return | propagate. Default: log-and-return
store-type: auto # auto | jdbc | in-memory | none. Default: auto
jdbc:
initialize-schema: embedded # embedded | always | never. Default: embedded
web:
key-header: Idempotency-Key # Header carrying the key. Default: Idempotency-Key
required: true # Reject a request that carries no key with 422. Default: true
in-flight-status: 409 # Status when another caller holds the key. Default: 409
max-body-bytes: 1048576 # Largest body the filter will fingerprint. Default: 1 MiB
filter-order: 0 # Order of the filter in the chain. Default: 0
purge:
enabled: true # Register the purge scheduler. Default: true
cron: "0 0 * * * *" # Cron for purging expired records. Default: hourlyProperties
idempotency.default-ttl=PT24H
idempotency.default-lease=PT30S
idempotency.default-wait=PT10S
idempotency.completion-mode=autonomous
idempotency.completion-failure-policy=log-and-return
idempotency.store-type=auto
idempotency.jdbc.initialize-schema=embedded
idempotency.web.key-header=Idempotency-Key
idempotency.web.required=true
idempotency.web.in-flight-status=409
idempotency.web.max-body-bytes=1048576
idempotency.web.filter-order=0
idempotency.purge.enabled=true
idempotency.purge.cron=0 0 * * * *Top level
| Key | Default | What it sets |
|---|---|---|
default-ttl |
PT24H |
How long a completed record stays replayable |
default-lease |
PT30S |
How long an acquisition is protected |
default-wait |
PT10S |
How long a second caller blocks. PT0S to not block |
completion-mode |
autonomous |
autonomous or join-transaction, for @Idempotent methods. The HTTP filter always completes on its own |
completion-failure-policy |
log-and-return |
log-and-return or propagate |
store-type |
auto |
auto, jdbc, in-memory or none |
The three durations are per-method overridable on
@Idempotent.
JDBC settings
| Key | Default | What it sets |
|---|---|---|
initialize-schema |
embedded |
embedded, always or never. See JDBC |
Web settings
| Key | Default | What it sets |
|---|---|---|
key-header |
Idempotency-Key |
Header carrying the key |
required |
true |
Reject a request with no key, with 422 |
in-flight-status |
409 |
Status when another caller holds the key |
max-body-bytes |
1048576 |
Largest body the filter will fingerprint |
filter-order |
0 |
Order of the filter in the chain |
Purge settings
| Key | Default | What it sets |
|---|---|---|
enabled |
true |
Register the purge scheduler |
cron |
0 0 * * * * |
Cron for purging expired records. Hourly |
Precedence
Three levels, nearest wins:
- The annotation attribute, when not empty -
@Idempotent(lease = "PT60S"). - The property, for every method that left the attribute empty -
idempotency.default-lease. - The built-in default, shown in the tables above.
key, scope and codec have no property level: a key is per-method by nature, a codec
belongs to the method’s return type, and an empty scope means “derive it” rather than “take
the application default”.
What is not configurable here
The properties above are the whole Spring surface. Store-level tuning is not exposed through them, because it differs per backend and belongs to the store rather than to the application.
That is not a gap - it is where those settings live. To change them, declare the store bean yourself and configure it:
- Redis - poll interval, purge batch sizing and replica acknowledgement are on
RedisIdempotencyStoreConfig. See Redis. - JDBC - the
initSchemaflag, the poll interval and the connection resolver are constructor arguments when you build the store by hand. See JDBC.
A store bean you declare always wins; the starter never replaces one. Every property above
keeps working when you do, except store-type and jdbc.initialize-schema, which only apply
to a store the starter builds.
Validation
Values are validated where they are bound, and the failure names the value it received rather
than only the key - defaultTtl must be at least 1ms, got: PT0S. Durations are ISO-8601, so
thirty seconds is PT30S. The cron expression is Spring’s six-field form, seconds first.
Malformed configuration fails the context at startup. See troubleshooting.