Retries Without Regret: Idempotency Keys in Spring Boot and Node
A popular DEV discussion recently asked to retry or not to retry . The honest answer is: retry, but only once you've made it safe. On mobile networks, where requests time out after the server has already done the work, the dangerous case isn't "the request failed". It's "the client doesn't know whether it succeeded." This post covers three things: Which requests are safe to retry by definition.…
Retries Without Regret: Idempotency Keys in Spring Boot and Node
Retrying requests is often necessary, but it must be done safely. On mobile networks, requests can time out while the server has already completed the work. The dangerous scenario is when the client is unaware if the request succeeded. This article covers three key points: which requests can be safely retried, how to make unsafe requests safe using idempotency keys, and how to retry politely with exponential backoff and jitter.
HTTP methods like GET, HEAD, OPTIONS, PUT, and DELETE are idempotent, meaning making several identical requests has the same effect as making just one. POST and PATCH are not idempotent. RFC 9110 defines idempotent methods to be retried with backoff. For POST requests, an idempotency key can be used to retry with the same key. Requests with 4xx, 429, or 503 status codes should be retried, with 429 and 503 honoring the Retry-After header and adding jitter.
Idempotency keys are a simple pattern popularized by payment APIs like Stripe. Clients generate a unique key (UUID) for each logical operation and include it in every request. The server records the key before performing the work. If the same key is encountered again, the server returns the stored result instead of performing the work again.
The table `idempotency_keys` has columns for the key, user ID, request hash, status, response code, response body, and timestamp. Keys should be scoped per user/client, and a hash of the request body should be stored to detect client errors. Inserting the key into the table atomically using `ON CONFLICT DO NOTHING` ensures only one concurrent request inserts the row, while others get zero rows back.
When a POST request is made with an idempotency key, the server checks if the key is claimed. If not, it inserts the key into the table and performs the business write and update status to 'done' in the same transaction. If the key is claimed, the server returns the stored result or a 409 Conflict if the request hash differs. If the request hash differs, a 422 error is returned. This approach ensures retries are handled safely and efficiently.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.