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

Spring HTTP timeout after POST: the write may already exist

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

A caller can time out after a remote service commits a write but before its response reaches the caller.

Download Spring source kit

The checked ordering

The loopback /remote-reservations handler records an Idempotency-Key and increments a write counter before it waits on a latch. The RestClient POST uses an 80ms read timeout, so the first call throws ResourceAccessException while the server still records one write. The test waits for a server-side commit signal before asserting the counter. That is the important order.

The first response may fail when the server later writes to a socket the client closed. The client exception cannot tell whether the reservation exists. The next fixture sends the same key again and checks the server-side deduplication rule.

Carry uncertainty into the API contract

A public receipt endpoint should not translate this transport failure into a claim that the remote write rolled back. It may return a retryable error with a stable command identifier, or reconcile the remote state before reporting a final decision. The exact response policy depends on the upstream contract.

The fixture is not a payment provider and has no database. Its in-memory key set intentionally models one server process. A real integration needs durable deduplication, retention rules, tenant scoping and behavior under simultaneous requests or restarts. The local H2 command fixture covers a different, transactional replay boundary.

Checked source

Java
String key = exchange.getRequestHeaders().getFirst("Idempotency-Key");
if (key != null && committedKeys.add(key)) {
    writes.incrementAndGet();
    firstWriteCommitted.countDown();
}

Verification boundary

RestClientBoundaryTest.aTimedOutWriteMayHaveCommittedBeforeTheCallerRetries.

Costs and limits

The remote state is an in-memory set in one loopback process. No durable upstream, concurrent duplicate race or network partition is checked.

Common Mistakes

  • Do not infer rollback from a client-side timeout.
  • Do not generate a new command key for the same uncertain write.
  • Do not treat an in-memory set as durable remote deduplication.

Read next

Spring HTTP replay key: two requests, one modeled reservation, Spring HTTP retries: only replay a command with a defined identity, Spring POST idempotency keys: bind replay to tenant and command, Spring transactional outbox: commit a receipt and event row together.

spring
restclient
http
Storage details