cloudsec: retry a code-scan push refused with 429, honouring Retry-After - #401
Merged
Merged
Conversation
A push is refused with 429 when the organization already has as many pushes in progress as it may (error_code ingest_busy) or the request quota is spent. Nothing is recorded for a refused push, so ingest_code_results now re-sends it: at least the response's Retry-After (clamped to 120s), exponential backoff without one, random jitter on top, at most 5 re-sends and 10 minutes of waiting. RateLimitError.retry_after is now filled from the header. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
lcbill
previously approved these changes
Sep 26, 2026
…sh gives up Non-ASCII digits and overlong values no longer escape as ValueError; the exhausted-retry error says how many times the push was refused instead of suggesting --retry, which does not apply to this path. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Contributor
Author
|
Self-review record (this repo does not use the automated review bot): I ran an adversarial review from a pristine
End-to-end check against a full local stack: the real SDK, installed from this branch, drove 12 concurrent pushes for one org against a service limited to one push at a time with a queue of one.
Leaving this for review. It is not merged. |
lcbill
approved these changes
Sep 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A code-scan push (
CloudSec.ingest_code_results, so bothcloudsec code ingestandcloudsec code scan --ingest) now re-sends a push that the API refuses with HTTP 429.The API answers 429 on this route in two cases:
error_code: "ingest_busy", withRetry-After), which a CI job pushing many repositories at once can hit;Neither one records anything, so sending the same push again is safe. Until now the CLI failed the CI job on the first one.
How it backs off
Retry-After, clamped to 120 s so a single header cannot park a job for an hour.Retry-After, it backs off exponentially: 5 s, 10 s, 20 s, 40 s, then 60 s.busy_retries=, and0restores the old behaviour) and 10 minutes of total waiting. After that theRateLimitErroris raised.--retry429 loop is turned off for this call (Client.request(..., retry_quota_errors=False)). Left on, it would ignoreRetry-After, skip the jitter and multiply the attempts.Supporting changes:
RateLimitError.retry_afteris now filled from theRetry-Afterheader. Both the seconds form and the HTTP-date form are read. When the header is absent the value isNone, not 0.Tests
tests/unit/test_code_ingest_busy_retry.pydrives the realClientwith onlyurlopenand the sleep replaced, so the header takes the same path it does against the API. The tests cover:busy_retries=0;--retry;I checked that the tests can fail. Each of these three changes breaks at least two of them:
Retry-After;Full suite:
pytest tests/unit/ tests/microbenchmarks/gives 4585 passed.The 429 with
Retry-Aftercomes from an API gateway change that ships separately. Against an API without it, busy pushes still come back as 400 and are not retried, which is the same behaviour as today.🤖 Generated with Claude Code