HTTP 429 Request Rate Too Large during Cosmos DB write retries
0 reputation · 10 Nov 2021, 08:58 UTC
0 reputation · 10 Nov 2021, 08:58 UTC
When implementing high-throughput write operations in Azure Cosmos DB, the SDK automatically handles transient failures, such as HTTP 429 (Request Rate Too Large), by retrying the request based on the x-ms-retry-after-ms header.
A critical design concern is ensuring that these retries do not result in duplicate records or unintended data overwrites when the initial request may have actually succeeded on the server despite a timeout or connectivity failure returning to the client.
While the Upsert operation and the use of a consistent id property provide a mechanism for idempotency, the behavior differs when integrating these with optimistic concurrency controls using ETags.
Upsert with If-Match headers during an automatic retry cycle?35775 reputation · 10 Nov 2021, 16:52 UTC
429 responses never indicate a committed write. When Cosmos DB returns HTTP 429 (Request Rate Too Large), the request exceeded the provisioned RU/s and the server did not apply the mutation. The SDK's automatic retry of a 429 is therefore inherently safe—it cannot create duplicates or overwrite state from that same request.
The duplicate-write risk comes from timeouts or network failures (408, 503, connection reset), where the client cannot know whether the server committed before the response was lost. Retrying such a write is safe only if the operation is idempotent.
x-ms-retry-after-ms header and waits that duration before retrying.MaxRetryAttemptsOnRateLimitedRequests and MaxRetryWaitTimeOnRateLimitedRequests in .NET v3/v4, Java v4, etc.).Upsert with a stable, client-generated id is idempotent for creates. Retrying the same upsert (same id, same payload) converges to a single document.
Adding If-Match (ETag) breaks that idempotency by design. If the first attempt actually succeeded but the client saw a failure (timeout, not 429), the document's ETag has changed. The SDK's retry sends the stale ETag, and the server correctly returns 412 Precondition Failed. This is optimistic concurrency working as intended—it detects the earlier success.
"order-12345-item-7") so any retry path collapses to one server-side effect.Upsert (no If-Match) for idempotent creates/updates.412 after a retry by re-reading the document, comparing content/ETag, and deciding whether to re-apply or treat as success.x-ms-retry-after-ms and that retried requests carry the same activity ID and payload.If-Match retry: commit a replace, re-issue the same request with the stale ETag, confirm 412 and that the document reflects the first write.CosmosDiagnostics to count retries and confirm whether a failed request reached the server (status vs. substatus and request charge).Which SDK language and version are you using (.NET v3/v4, Java v4, Node, Python)? Default retry limits and option names differ across generations, and the exact configuration surface changes the tuning steps.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.