Skip to content

Retry sidecar API 429s honouring Retry-After (30s budget)#417

Merged
danmux merged 2 commits into
mainfrom
dm-claude/429-retry-budget
Jun 25, 2026
Merged

Retry sidecar API 429s honouring Retry-After (30s budget)#417
danmux merged 2 commits into
mainfrom
dm-claude/429-retry-budget

Conversation

@danmux

@danmux danmux commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds RetryOn429Budget to httpcl.Config: retries HTTP 429 responses by honouring the Retry-After response header (integer seconds or HTTP date)
  • Retries stop and a RateLimitError is returned when elapsed + pending wait would exceed the budget, or when a single Retry-After value exceeds it — error message is agent-readable: "rate limited: server requests 45s back-off, retry budget of 30s exhausted — try again later"
  • Non-429 retry behaviour (5xx, network errors) is unchanged — a per-call counter caps those at the original 3-retry limit even though RetryMax is raised to 30 for 429 headroom
  • Fixes a resp.Body leak when retryablehttp returns both a response and a CheckRetry error
  • IsRateLimitError helper added for callers that need to distinguish rate-limit failures
  • CircleCI API client wired with a 30s budget, covering all sidecar API calls

Adds RetryOn429Budget to httpcl.Config. When set, the client retries
HTTP 429 responses honouring the Retry-After header (integer seconds
or HTTP date). Retries stop and a RateLimitError is returned when the
cumulative elapsed+wait time would exceed the budget, or when a single
Retry-After value exceeds it. Non-429 retry behaviour (5xx, network
errors) is unchanged — a per-call counter caps those at the original
3-retry limit even though RetryMax is raised to 30 for 429 headroom.

Also fixes a resp.Body leak when retryablehttp returns both a response
and a CheckRetry error.

The CircleCI API client uses a 30s budget, covering all sidecar calls.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Derive RetryMax from budget (budget/s + origMax) instead of
  hardcoding 30; prevents premature cap on budgets > ~30s
- Merge duplicate if-retryOn429Budget blocks in Call()
- Add TestRetryOn429_5xxStillCapsAtThreeWithBudgetSet: verifies
  non-429 retry cap is preserved when budget is configured
- Add client_internal_test.go covering all parseRetryAfter branches
  including HTTP-date format, past date, missing header, invalid value

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@danmux danmux merged commit 913b558 into main Jun 25, 2026
6 checks passed
@danmux danmux deleted the dm-claude/429-retry-budget branch June 25, 2026 14:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants