fix(base): honor Retry-After as a minimum instead of capping at 30s

Aperta
#289 0 commenti 0 reazioni 1 assegnatario Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

@ffumero2003 ci sta già lavorando.

Dal 3/11/2026.

Valutazione

Questa issue non è ancora stata valutata.

Descrizione

bug

Context

parseRetryAfterSeconds caps any Retry-After of 30 seconds or more to 30s (base/base.go:192), and Backoff() caps again at the same ceiling (base/base.go:238). The cap is intentional (comment at base/base.go:235), but B2 defines Retry-After as the wait before reissuing the command, so capping it means the client retries sooner than the server explicitly asked. Under load that amplifies pressure on a service that is already shedding it, and tends to produce repeated 503s.

Evidence

A synthetic 503 with Retry-After: 120 produced base.Backoff(err) == 30s.

Decision required

Honoring the delay is a one-line behavior change, but it carries a policy choice:

  • (a) Treat Retry-After as a minimum and wait the full requested delay, bounded by a configurable maximum total elapsed time / attempt budget; or
  • (b) When the requested delay exceeds the caller's budget, defer or return the error rather than silently retrying sooner (this matches OpenAI's current retry guidance).

Either way the client must never retry sooner than the server requested.

Acceptance criteria

  • R1. The client never retries sooner than a server-provided Retry-After.
  • R2. Total wait / attempts are bounded (configurable, or via context cancellation) so a hostile or very large delay cannot hang an operation indefinitely.
  • R3. Tests assert that a long Retry-After (for example 120s) is either honored or surfaced as a returned error, not truncated to 30s.

In scope

  • Retry-After parsing, base.Backoff, and the bounded-wait policy described in this issue, with focused regression tests.
  • The choice between honoring the delay within a budget and returning/deferring when it exceeds the budget remains the decision described below.

Out of scope

  • Unrelated work outside the components and behavior described in In scope.

Verification

Run the repository regression checks with live credentials unset:

unset B2_APPLICATION_KEY_ID B2_APPLICATION_KEY B2_ACCOUNT_ID B2_ACCOUNT_KEY
go build ./...
go vet ./...
go test -race -count=1 ./base ./b2/...
  • Use the synthetic 503 with Retry-After: 120 from Context. Show that the delay is honored or that the caller receives the budget/cancellation error; it must not be silently truncated to 30s.
  • Record which of the existing policy alternatives is implemented, and prove the selected total-wait/attempt bound.
  • Expected result: the checks above succeed and the observable outcomes in Acceptance criteria are demonstrated. If a check cannot run, report Could not run because: ...; if it starts but fails, report Could not complete because: .... A skipped check is not a pass.

Links

  • base/base.go:184-196 (parseRetryAfterSeconds)
  • base/base.go:235-239 (Backoff cap)
  • Related error-handling work: #288
Lingua principale
Go
Stelle
66
Fork
18
Merge medio
1g 10h
PR unite (30g)
132

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di Backblaze/blazer

Tutte le issue di Backblaze/blazer

Issue simili

Altre issue su Go

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.