Skip to content

Bound registry downloads by ApiTimeouts instead of a 60 s total deadline (#872) - #876

Open
Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
mainfrom
arch-refactor/872-registry-timeouts
Open

Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
mainfrom
arch-refactor/872-registry-timeouts

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

LLM Description written by Claude Code:claude-opus-5-5

Fixes #872

Summary

Hosted upstream restore (rollback, the vendor takeover) and vendored Maven built their registry clients with a 60 s whole-request deadline and no connect bound, so a slow but progressing download of an original tarball, Go module zip, NuGet document or jar was aborted at 60 s. Both now build through one registry_fetch::registry_client_builder under the shared ApiTimeouts policy (10 s connect, 60 s of silence reset per chunk, no total deadline), and registry_fetch::download reads through utils::http::read_capped.

Why

  • Issue #872, register row C49 in register/20-audit-core.md, living document §7 "Other HTTP stacks" (doc/07-infra-agent.md).
  • Leverage: B = 1 (p1 bug), U = 0, D ≈ 2.1 (the last hand-rolled copy of read_capped and Maven's second registry Client::builder), R = L. Score ≈ 5.1, first in the refactor queue.

What changed

  • vendor/registry_fetch.rs: new registry_client_builder(user_agent) applies ApiTimeouts; build_registry_client uses it. download keeps its http(s) and status checks, then calls read_capped(resp, MAX_DOWNLOAD_BYTES, "registry artifact"). A #[cfg(test)] thread-local test_timeouts override shortens the bounds in tests.
  • vendor/maven_repo.rs: fetch_registry_bytes builds through registry_client_builder(MAVEN_USER_AGENT), so it keeps its Maven user agent.
  • Base-red port: main fails utils::digest::tests::production_digests_go_through_the_helpers because Full Gradle support in agent, hosted and vendored modes #646 landed inline digests after the ratchet. patch/jvm_jar.rs's private sha1_hex/sha256_hex and the Maven sidecar's inline sha1 now call utils::digest::{sha1_hex_of, sha256_hex_of}. crawlers/gradle_cache.rs joins PENDING_INLINE_DIGESTS rather than being edited, because open sbt, Mill and scala-cli support in agent, hosted and vendored modes #690 changes it. Hashes are byte-identical.

Deviation from the issue: Maven still builds a client per fetch (now through the shared builder) rather than one per process. A process-global reqwest::Client keeps pooled connections bound to the tokio runtime that opened them, which breaks across the many per-test runtimes. Each Maven vendor run makes only a handful of fetches.

Deleted

  • The hand-rolled declared-length and streamed-cap loop in registry_fetch::download.
  • Maven's own Client::builder().timeout(60 s) and the Duration import.
  • jvm_jar.rs's two private digest helpers.
  • git diff --stat origin/main: 5 files, +165 / −55. Production ≈ +55 / −60; tests ≈ +91 / −1.

Behavior

  • Registry fetches no longer have a 60 s total deadline. They now fail after 10 s without a connection, or after 60 s with no bytes.
  • Cap refusals in download now use read_capped's wording (registry artifact too large: declared N bytes > CAP cap / … exceeded CAP-byte cap mid-stream), prefixed with the URL. The caps themselves are unchanged.
  • Nothing else changes: no JSON, exit-code or contract changes.

Test evidence

  • New registry_clients_have_no_total_deadline: with the idle bound shortened to 400 ms, a body that trickles for 1.6 s arrives whole through both build_registry_client + download and Maven's fetch_registry_bytes.
  • New registry_clients_fail_a_body_that_stalls_past_the_idle_bound: a body that goes silent for 5 s mid-stream fails at the idle bound through both clients. Red→green: with the builder reverted to the old .timeout(60 s) it FAILS (both fetches wait out the stall and succeed); on the branch it passes.
  • One-off, not committed, at the default bounds: a 70 s trickle (1 KiB/s). Old builder: both clients fail at 60.0 s (error decoding response body). Branch: both return all 71 680 bytes in ≈70.1 s.
  • cargo test -p socket-patch-core --lib: 5248 passed, 4 failed. The 4 are the known root-only sandbox failures (relax_loop_must_not_traverse_symlinked_root, an_unremovable_hidden_lock_keeps_every_store_entry, wire_write_failure_maps_error_and_leaves_lock_untouched, wire_failure_rolls_back_already_written_files), which also fail on main. production_digests_go_through_the_helpers fails on main and passes here.
  • cargo test -p socket-patch-cli --all-features --test in_process_rollback_hosted --test maven_sidecar_cli: 23 + 8 passed.
  • cargo clippy --workspace --all-features -- -D warnings: clean.
  • CI on 28d4d52 at 18:42Z: 412 checks passed, 0 failed (including coverage, clippy and test (macos-latest)); 24 Gradle and Windows jobs still running. Bugbot found no issues on 28d4d52.

Risk

Low. The transport bounds follow the policy the patch-API clients have used since #581. The download cap and its checks are unchanged.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DBN2DxcmTxCSNfaHk2oxu2


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko Mikola Lysenko (mikolalysenko) added refactor Structural change: duplicated code or logic, missing abstraction, layering, dead code arch-refactor PR opened by the scheduled architecture refactor routine labels Oct 5, 2026
Hosted upstream restore (rollback, vendor takeover) and vendored Maven
built their registry clients with a 60 s whole-request deadline and no
connect bound, so on a slow link an original tarball, module zip or jar
that took over a minute to download failed with a transport error even
while bytes were still arriving, and a black-holed host held the run
for the full minute.

Both now build through one registry_fetch::registry_client_builder
that applies the shared ApiTimeouts policy: 10 s connect plus 60 s of
silence, no total deadline. registry_fetch::download reads the body
through utils::http::read_capped, deleting the last hand-rolled copy of
the capped reader; the cap and its checks are unchanged, only the
refusal wording now matches the other capped downloads.

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.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 5, 2026 18:21
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

Mikola Lysenko (mikolalysenko) pushed a commit that referenced this pull request Oct 5, 2026
Assisted-by: Claude Code:claude-opus-5-5

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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 28d4d52. Configure here.

@mikolalysenko Mikola Lysenko (mikolalysenko) added the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Oct 5, 2026
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Burn-down agent: labeled Ready for review at 28d4d52 (28d4d52828147c187e08fe0509bf38635c77d201).

  • CI: 457/457 green on the head commit (6 skipped by matrix rule), including the last Windows Gradle 7.6.6 job.
  • Bugbot: reviewed 28d4d52 with no findings; no open review threads.
  • Mergeable against main (clean). Already approved by Tanmay Singla (@Tanmay182003) on this SHA.

Generated by Claude Code

Mikola Lysenko (mikolalysenko) pushed a commit that referenced this pull request Oct 5, 2026
#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

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-refactor PR opened by the scheduled architecture refactor routine Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review refactor Structural change: duplicated code or logic, missing abstraction, layering, dead code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Registry downloads give up after 60 s even while the body is still arriving

3 participants