Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Spring HTTP retries: only replay a command with a defined identity

Last updated: 30 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

A timeout after sending a remote write leaves its result uncertain, so retry safety depends on the upstream command contract.

Download Spring source kit

Differentiate reads from writes

A bounded GET may be repeated after a transient connection failure if the read has no side effect and the deadline permits another attempt. A POST that creates a payment or reserves inventory cannot be retried blindly. The remote side may have committed before the response was lost. Attach a stable command identifier only when the upstream accepts and enforces it.

The local POST fixture stores a response against a key but lives in one process. The tenant command fixture puts replay state in the same H2 transaction as the mutation. Neither proves the behavior of an external risk or payment service.

Treat retry as a state machine

Track original request, uncertain result, retry attempt, duplicate response and final reconciliation. Enforce a total deadline and an attempt cap. Retry only the failure classes that the upstream contract permits; a validation error should not enter a backoff loop. If the upstream cannot deduplicate, create a reconciliation path instead of claiming safe replay.

A consumer that receives an outbox event twice has the same identity problem. The event-ID ledger commits deduplication with its local mutation. The source kit now calls a local HTTP handler over loopback. It shows a write before timeout and a same-key replay against an in-memory deduplicating server; it still does not call a real downstream provider or prove durable deduplication.

Working sketch

http
POST /remote-reservations
Idempotency-Key: receipt-2048-tenant-east
# Reuse the same key only for the same normalized command.

Verification boundary

RestClientBoundaryTest.aTimedOutWriteMayHaveCommittedBeforeTheCallerRetries checks a sequential loopback replay; no external provider or distributed retry is tested.

Costs and limits

No production remote service, distributed failure injection or cross-system reconciliation test is present.

Common Mistakes

  • Do not generate a new key on every retry of the same command.
  • Do not replay an uncertain write against a server without a deduplication contract.
  • Do not retry validation failures as transient outages.

Read next

Spring POST idempotency keys: replay the same receipt result, Spring POST idempotency keys: bind replay to tenant and command, Spring consumer idempotency: reserve an event ID with the stock mutation, Spring HTTP client timeouts: bound the call inside the request deadline.

Checked outbound HTTP continuation

Continue with Spring HTTP timeout after POST: the write may already exist, Spring HTTP replay key: two requests, one modeled reservation.

spring
spring-boot
release
Storage details