Make base error classification method-aware so non-idempotent calls are not re-sent
I maintainer di solito rispondono entro 1 giorno
@ffumero2003 ci sta già lavorando.
Dal 8/11/2026.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 45/100
Direzione di ricerca
Start with base/base.go and the classification tests in base/action_test.go; trace how Action, MaxRetries and transport errors handle method names and request timing. Check the existing copy tests and public API retry behavior described in the issue. Done when the acceptance criteria pass for the listed methods, including OutcomeUnknown and errors.Is checks.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Context
This is a follow-up to Backblaze/blazer#167 (merged, closes #165). Since #167, base.Action returns Retry for 408 on every non-upload method and for 429, 500, 502, 503 and 504 on every method, including calls that are not safe to repeat: b2_create_key, b2_copy_file, b2_hide_file, b2_finish_large_file, b2_delete_file_version, b2_update_bucket and others. A 502 or 504 comes from a gateway and does not say whether B2 applied the request, so a write that already succeeded is sent again. base.Action, base.MaxRetries and base.Backoff decide this for the b2 package and for programs that use base directly, and they never look at whether the method is safe to repeat. This issue asks that the retries added in #167 (and the existing 500 and transport retries) be limited to calls that are safe to repeat.
Current behavior
At a5e0d13:
- base/base.go:94-100: 408 returns
Retryfor every method exceptb2_upload_file/b2_upload_part(94-98); 429, 500, 502, 503 and 504 returnRetryfor every method (99-100). 5xx and transport failures on uploads returnAttemptNewUpload(71-73, 76-78), which can store a second version. - base/base.go:518-558: every transport failure except certificate verification errors, including a reset or timeout after the request was written, becomes
b2err{retry: 1}(552-556), soActionreturnsRetry(69-75); the method name is cleared for non-upload calls (532-534). - base/base.go:213-224:
MaxRetriesis 20 for uploads and downloads and 5 for everything else. base/base.go:230-242:Backoffis theretryvalue in seconds, so 1 s for transport errors. - Tests added in #167 expect this for
b2_copy_partandb2_copy_file: base/action_test.go:69-99, b2/copy_test.go:117-126, b2/compose_extended_wire_test.go:740 and 742.
Reproduced at a5e0d13 through the public b2 API with an httptest server that fails the first call once and then succeeds:
status b2_create_key b2_copy_file b2_hide_file b2_update_bucket b2_delete_file_version
408 2, err=nil 2, err=nil 2, err=nil 2, err=nil 2, err=nil
500 2, err=nil 2, err=nil 2, err=nil 2, err=nil 2, err=nil
502 2, err=nil 2, err=nil 2, err=nil 2, err=nil 2, err=nil
504 2, err=nil 2, err=nil 2, err=nil 2, err=nil 2, err=nil
Before #167 (7888c5b), the same test sent each call once for 408, 502 and 504 and returned the error. If the first b2_create_key was applied, the second creates a second key; the caller only ever sees one secret.
Expected behavior
A failure on a call that is not safe to repeat, after the request may have reached B2, is reported as "outcome unknown" and not re-sent automatically. Failures before the request was sent, 429 and 503 stay retryable, and #167's retries stay for calls that are safe to repeat.
Acceptance criteria
- R1. A 500, 502, 504 or a mid-request connection close on
b2_create_key,b2_hide_file,b2_copy_file,b2_finish_large_fileandb2_delete_file_versiongivesOutcomeUnknown,MaxRetries == 0anderrors.Is(err, base.ErrOutcomeUnknown). - R2. A refused connection, a 429 and a 503 on the same methods give
Retry. - R3.
b2_list_file_names,b2_get_file_infoand downloads keepRetryfor 408, 500, 502, 503 and 504.
In scope
Proposed change
- Keep the method name and the original error on every
b2err. - Record whether the failure happened before send (dial, DNS, TLS handshake) or after (reset, EOF, read timeout).
- Export an idempotency table, for example
base.Idempotent(method string) bool: reads, upload URL calls, authorize,b2_set_bucket_notification_rulesand downloads are idempotent; create key/bucket, hide, copy file, start/finish/cancel large file, deletes andb2_update_bucketwithifRevisionIsare not. If repeatingb2_copy_partwith the same part number simply replaces the part (not confirmed here), it belongs on the idempotent list and theComposeretries from #167 stay. - Add an
ErrActionsuch asOutcomeUnknownand a sentinelbase.ErrOutcomeUnknownfor a post-send failure or a 500, 502 or 504 on a non-idempotent method;MaxRetriesreturns 0 for it. If B2 never returns 408 after applying a request (not confirmed here), 408 can stayRetry. - For uploads, keep
AttemptNewUploadfor pre-send failures and 503, document that other retries may create a second version, and let callers opt out (useful with Object Lock).
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 supplied status-method matrix and controlled pre-send/post-send transport failures. Assert
Action,MaxRetries,errors.Is, and exact request counts for the acceptance cases. - Preserve the stated read and 429/503 controls. Record the unresolved 408/copy-part safety decisions without treating their assumptions as already confirmed.
- 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, reportCould not complete because: .... A skipped check is not a pass.
Links
Backblaze/blazer#167 (merged, closes #165) added the 408, 502 and 504 retries described above. Backblaze/blazer#101 (open: 401 unauthorized treated as an expired token) covers only the reauthorization replay. Backblaze/blazer#145 (merged) synchronized authorization state and did not change classification. Backblaze/blazer#18 and #31 bounded the retry count. Backblaze/blazer#117 and #129 added calls that go through the same retry path.
- Lingua principale
- Go
- Stelle
- 66
- Fork
- 18
- Merge medio
- 1g 10h
- PR unite (30g)
- 132
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di Backblaze/blazer
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
I maintainer di solito rispondono entro 1 giorno
-
Bucket.Attrs never returns ReplicationConfig: replication configuration is write-onlyForse di nuovo libera Una pull request per questa issue è stata chiusa senza essere unita. Apertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
I maintainer di solito rispondono entro 1 giorno
-
test: skip the fuzz non-vacuity guard when replaying a single seedForse già presa @ffumero2003 l’ha presa 5 giorni fa. Apertatesting
Backblaze/blazer#330 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di Backblaze/blazer
Issue simili
-
needs-triage typo
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 88/100
llm-d-incubation/llm-d-scaling-manager#122 ·
I maintainer di solito rispondono entro 1 giorno
-
good first issue severity: low tech-debt
Difficoltà 2/5 Mezza giornata Idoneità per principianti 75/100
TMHSDigital/subenum#329 ·
I maintainer di solito rispondono entro 1 giorno
-
[Bug] Backend summarize min() / max() panics when a field has no numeric valuesForse già presa @weng5e l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 64/100
grafana/grafana-infinity-datasource#1832 ·
I maintainer di solito rispondono entro 1 giorno
-
tech-debt
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
GillMacedo/godebugdiff#13 ·