Gateway retry can repeat downstream work and retain a request body; both costs need an explicit route policy.
Spring Cloud Gateway retry: idempotency, buffered bodies and the byte budget
Retries change the command contract
A timed-out POST may have committed an order even though the gateway never received its response. Blindly sending the body again can create a second order. The Gateway Retry filter defaults are centered on GET and selected 5xx or exception cases; enabling POST is an explicit decision. For writes, require a stable idempotency key and enforce it in the downstream database, as in the receipt command. A gateway header alone cannot guarantee once-only effects.
Bound retained bytes
When a route retries a request that has a body, Gateway can cache that body to replay it. A 12 MiB upload multiplied by 47 concurrent attempts is already hundreds of MiB before other routing overhead. Put a RequestSize limit ahead of retry-sensitive routes, and prefer sending large uploads directly to a storage path with its own retry contract. Upload limits should be tested at the edge and application layers.
Exercise the uncertain result
Make the downstream commit a write, then drop the response. The client should see a known uncertainty policy rather than an invisible duplicate. Check filter ordering with the combined chain, because filters after Retry can run again. A test should cover retry count, body size rejection, timeout and a duplicate idempotency key.
Implementation sketch
- id: catalog-read
uri: http://catalog-service
predicates:
- Path=/api/catalog/**
filters:
- name: RequestSize
args:
maxSize: 2MB
- name: Retry
args:
retries: 2
methods: GET
statuses: BAD_GATEWAY,SERVICE_UNAVAILABLECost and verification
Two retries can turn one request into three downstream attempts. Body replay retains bytes; backoff and client timeouts must fit one end-to-end latency budget.
Common Mistakes
- Do not enable POST retry without downstream idempotency enforcement.
- Do not let a large body be replayed without a size limit.
- Do not mistake an upstream timeout for proof that no write committed.
Read next
Spring POST idempotency keys: replay the same receipt result, Spring multipart size limits: enforce parser and application budgets, Spring Cloud Gateway filter order: pre and post phases reverse, Spring HTTP timeout after POST: the write may already exist.
