Read this before adopting rather than after. If one of these is a problem for you, it is better found now.
| Limitation | Does it rule the library out for you? |
|---|---|
| No reactive support | Yes, if your application is WebFlux-only. Nothing registers and nothing warns you |
| No tenant isolation | No, but you must prefix keys yourself on a multi-tenant public API |
| No Redis Cluster | Yes, if Cluster is the only Redis you run. Standalone and Sentinel work |
| Beans in a circular reference | No. Spring Boot forbids circular references by default |
| Downstream side effects | No, but it is the thing most often expected and not provided |
| Buffered request bodies | Yes, for streaming upload endpoints. Do not annotate them |
The rest of this page is each row in full.
No reactive support
The HTTP adapter is built on OncePerRequestFilter (Servlet API), and the engine’s execute
is blocking.
Spring WebFlux is not supported: nothing registers, and no error is raised. An application that is WebFlux-only gets no idempotency from the HTTP adapter and no warning that this is the case.
No tenant isolation
Records are scoped per method, but within a scope there is no built-in per-tenant or per-user isolation: two callers using the same key in the same scope share idempotency state.
Prefix keys at the application level where that matters, for example userId:clientKey.
This is worth taking seriously on a public API. A client that generates keys from a sequence
rather than a UUID will collide with another tenant’s keys, and the second tenant gets the
first tenant’s stored response replayed to them, or a 422 if their request body differs.
Prefixing the key is the fix, and it is
yours to apply.
Redis Cluster is not supported
The provider takes Lettuce’s non-cluster StatefulRedisConnection, and its bounded SCAN
purge is not node-aware. Standalone and Sentinel master-replica connections work.
Beans in a circular reference are not advised
The advice is applied by a bean post-processor, which - like @Async - cannot reach a bean
that was injected into its own dependency cycle before it was post-processed. Spring Boot
forbids circular references by default, so this only matters where they have been allowed.
Downstream side effects
This is not an exactly-once guarantee for arbitrary downstream side effects. Lease fencing protects the idempotency record, not the third-party charge your action made just before the process died. If you need that guarantee you still need a shared transaction, a transactional outbox, or an idempotency key passed to the downstream service. This library makes your work safe to retry; it cannot make someone else’s endpoint safe to retry for you.
The practical version: annotate your payment endpoint, and also pass the payment provider its own idempotency key. The library stops your handler running twice. Only the provider can stop the provider charging twice.
Where the first execution published messages downstream, store their ids in a payload’s
attributes so the duplicate can reference them instead of republishing - see
payloads and codecs.
Buffered request bodies over HTTP
The filter buffers the request body so it can fingerprint it and still hand it to your
handler, which means Servlet non-blocking reads are unsupported on an annotated endpoint and
the body is held in memory up to idempotency.web.max-body-bytes. Streaming upload endpoints
should not be annotated. See HTTP endpoints.
Also not
It is not a distributed lock you can borrow for general use. The HTTP adapter is Servlet-only. The in-memory store is not for more than one instance, and Redis cannot join your transaction.
Spring Boot 3
0.4.0 moved to Spring Boot 4. Boot 3 applications stay on 0.3.0 - see upgrading.