Honor HTTP-date Retry-After on vendor-service retries through api::retry (#677) - #889
Mikola Lysenko (mikolalysenko) wants to merge 3 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
A vendor-service 429 or 503 that sent Retry-After as an HTTP-date was retried on the 400 ms backoff, because the vendor path kept its own delta-seconds-only parser. Vendor retries now read Retry-After through api::retry::parse_retry_after on the client's RetryHooks clock (still capped at VendorRetryPolicy::max_delay), and draw their ±25% jitter from the seeded api::retry::jitter_sample, keyed by request and attempt, and wait on the hooks' sleep. The private retry_after_secs and jitter_sample copies in client.rs are deleted. New tests run the reference POST, the archive GET, the capped artifact GET and a resumed deferred GET through the shared parser, and pin the cap and the seeded jitter. Assisted-by: Claude Code:claude-opus-5-5
#646 landed inline sha1/sha256 computations in patch/jvm_jar.rs, patch/sidecars/maven.rs and crawlers/gradle_cache.rs after the utils::digest ratchet, so production_digests_go_through_the_helpers fails on main. jvm_jar's private sha1_hex/sha256_hex copies and the Maven sidecar's inline sha1 now call the shared helpers; gradle_cache.rs, which an open PR also edits, joins the pending list for now. Hashes are byte-identical. Ported from #876 so this PR's CI is not red on the base-red ratchet. (cherry picked from commit 28d4d52) Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 1d752aa. Configure here.
|
[agent] CI on Generated by Claude Code |
|
Burn-down agent: labeled Ready for review at
Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #677
Summary
Vendor-service retries (the package-reference POST, the archive GET, the capped artifact GET and a resumed deferred GET) now read
Retry-Afterthroughapi::retry::parse_retry_afterand draw their jitter from the seededapi::retry::jitter_sample, on the client'sRetryHooks. The private, weaker copies inapi/client.rsare deleted.Why
Register row C15 (child 1 of tracking #676), living document
doc/07-infra-agent.md("Three retry systems in one module"). Leverage: B 0 (no separate bug issue), U 1 (child 2 of #676, which merges the retry loops, needs this), D ≈2 (retry_after_secs,jitter_sample()), R L. Score ≈4. It was the best candidate that no open PR overlaps.What changed
ApiClient::vendor_retry_hint(status, headers): retryable status →parse_retry_after(headers, hooks.now_unix_secs()). It replaces the threevendor_status_retryable(..).then(|| retry_after_secs(..))sites.vendor_backoff(key, retry, retry_after)takes jitter fromretry_jitter(hooks.jitter_seed, key, retry), keyed by the archive or artifact URL, or by a constant key for the reference POST. It waits onhooks.sleep, which is tokio's sleep by default.VendorRetryPolicy::delaystill maps the sample onto ±25% and caps atmax_delay.retry_after_secs(delta-seconds only) andjitter_sample()(unseededRandomState).28d4d52, cherry-picked unchanged):production_digests_go_through_the_helpersfails onmainbecause Full Gradle support in agent, hosted and vendored modes #646 added inline JVM digests. This is the same change Bound registry downloads by ApiTimeouts instead of a 60 s total deadline (#872) #876 carries, so it becomes a no-op once that PR lands.Size (
git diff --stat)api/client.rs: production +36 / −36 (net 0 after rustfmt wrapping; the two helpers are gone), tests +173 / −2.jvm_jar.rsandsidecars/maven.rs, plus 1 line in the test ratchet.Behavior
Retry-Afteris an HTTP-date now waits until that date, still capped atmax_delay(4 s by default). Before this, it fell back to the 400 ms → 4 s backoff.vendor_status_retryable), same attempt counts and request sequences.Test evidence
every_vendor_retry_loop_honors_an_http_date_retry_after: all four former callers wait exactly 2 s onRetry-After: <date 2 s ahead>. Newan_http_date_retry_after_is_capped_at_max_delaycovers the cap. Newvendor_backoff_jitter_replays_from_the_hook_seed: the same seed gives the same waits, another seed gives different ones, and every wait stays within ±25% of nominal.cargo clippy --workspace --all-features -- -D warnings: clean.cargo test -p socket-patch-core --lib: 5249 passed. The 4 known root-only failures remain (copy_tree::relax_loop_must_not_traverse_symlinked_root,vlt_heal::an_unremovable_hidden_lock_keeps_every_store_entry,pypi_poetry::wire_write_failure_…,pypi_requirements::wire_failure_…).cargo test -p socket-patch-cli --all-features --test covgap_commands_vendor --test cli_scan_silent --test covgap_commands_get: all pass except 3 tests that need a read-only directory and fail when run as root in the sandbox (*_state_write_failure_*incovgap_commands_vendor; they chmod a directory). These pass in CI.Risk
Low. One file of production code. The vendor retry suites (
vendor_retry_tests,vendor_prefetchtests) pass with unchanged request sequences.🤖 Generated with Claude Code
https://claude.ai/code/session_01HegUKEf6caV6QASRt7z8iX
Note
Low Risk
Retry timing and jitter change for vendor HTTP calls only; behavior is tightened (HTTP-date support) with broad test coverage and unchanged retry status sets.
Overview
Vendor-service retries (package-reference POST, archive GET, capped artifact GET, and resumed deferred downloads) now use the shared
api::retrypath forRetry-Afterand backoff timing instead of local helpers.Retry-Afteris parsed viaparse_retry_afteron the client’sRetryHooksclock, so HTTP-date values are honored (still capped atVendorRetryPolicy::max_delay), not only delta-seconds. Backoff waits usehooks.sleep; jitter comes from the seededretry_jitterkeyed by request (constant for the reference POST, URL for downloads). Localretry_after_secsand unseededjitter_sample()are removed; hint logic is centralized invendor_retry_hint.JVM jar patching and Maven sidecars switch inline SHA-1/SHA-256 hex helpers to
utils::digest::{sha1_hex_of, sha256_hex_of}, with a small test ratchet update. New wiremock tests cover HTTP-dateRetry-Afteracross all four retry loops, cap behavior, and deterministic jitter from the hook seed.Reviewed by Cursor Bugbot for commit 1d752aa. Configure here.
Generated by Claude Code