Skip to content

feat(cache): upload to the remote cache in the background and support HTTP/2 - #787

Open
wan9chi wants to merge 7 commits into
mainfrom
claude/background-remote-cache-uploads
Open

wan9chi wants to merge 7 commits into
mainfrom
claude/background-remote-cache-uploads

Conversation

@wan9chi

@wan9chi wan9chi commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

Motivation

In read-write mode, a task waited for its upload to the remote cache before it counted as finished, so every task that depended on it waited too. A slow remote cache slowed down the whole run, even though nothing in the run needed the upload. Once uploads run side by side, HTTP/1.1 also opens a connection for each one; HTTP/2 lets them share one.

Changes

  • Background uploads. Once a task's result is cached locally, its upload starts in the background and the task finishes right away. When the graph is done, vp run prints Waiting for N remote cache uploads to finish (Ctrl-C to cancel)... and waits for them before the summary. An upload's error is set later, through the Arc<OnceLock<UploadError>> in CacheUpdateStatus::Updated, and the summary reads it after the wait.
  • Cancellation. A new interrupt token, which only Ctrl-C cancels, cancels the uploads. Their entries stay in the local cache, and the summary says they weren't uploaded because they were interrupted. Fast-fail still stops lookups but no longer stops uploads, so tasks that succeeded before another one failed are still uploaded. docs/cancellation.md covers both.
  • HTTP/2. reqwest's http2 feature is on. HTTPS endpoints use HTTP/2 if the server accepts it in the TLS handshake and HTTP/1.1 otherwise. http:// endpoints stay on HTTP/1.1.
  • Tests. Whether an upload is still running when the graph is done depends on how fast the remote cache responds. So e2e steps that upload set VP_RUN_INTERNAL_HIDE_PENDING_UPLOADS, which keeps the waiting line out of their output, including the first step of restore_failure from fix(cache): fail the run when a cache hit's outputs can't be restored #770. remote-cache-server takes --stall ROUTE, which reads requests to the route but never answers them, so the cases that show the waiting line or cancel uploads use --stall /store. Like the other backend cases, they need Node.js and are skipped on Windows. New e2e cases: pending_uploads, hide_pending_uploads, ctrl_c_during_upload, and fast_fail_during_upload. A unit test checks that the client offers h2 over TLS.

Notes for reviewers

  • Uploads aren't capped. Each upload in progress holds its encoded entry in memory and its output archive open, plus its own connection on HTTP/1.1, and none of that counts against --concurrency-limit. A large graph with a slow endpoint can pile them up. A cap is left for a follow-up.
  • No HTTP/3. reqwest's http3 feature needs --cfg reqwest_unstable in every build, vite-plus included, adds aws-lc-rs next to ring, bypasses proxies, and is used only when the client forces HTTP/3 for every request.

🤖 Generated with Claude Code

wan9chi and others added 3 commits October 2, 2026 11:45
A task no longer waits for its upload to the remote cache, so tasks that
depend on it start right away. Once all tasks are done, vp run waits for
the uploads still running and says how many there are. Ctrl-C cancels
them, and the summary warns that they weren't uploaded. Fast-fail
doesn't cancel them, so tasks that succeeded before another one failed
are still uploaded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Enable reqwest's http2 feature. HTTPS endpoints use HTTP/2 if the server
accepts it during the TLS handshake and HTTP/1.1 otherwise. HTTP
endpoints stay on HTTP/1.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

fspy benchmark

linux

dynamic/launch             change  +0.38%  [ -5.66% ..  +6.57%]  overhead  +296.59%
dynamic/access             change  -0.29%  [ -2.38% ..  +1.21%]  overhead   +13.25%
dynamic/access-relative    change  +0.56%  [ -1.63% ..  +1.65%]  overhead   +60.00%
dynamic/access-contended   change  +3.37%  [-10.10% .. +22.50%]  overhead   +22.03%
static/launch              change  +0.41%  [ -5.60% ..  +5.70%]  overhead  +730.87%
static/access              change  +0.16%  [ -7.20% ..  +7.71%]  overhead  +821.90%
static/access-relative     change  -0.11%  [ -6.59% ..  +4.79%]  overhead +1308.93%
static/access-contended    change  +3.35%  [ -6.12% .. +13.27%]  overhead +2234.33%

macos

dynamic/launch             change  -0.07%  [ -4.82% ..  +4.95%]  overhead  +238.74%
dynamic/access             change  +1.36%  [ -9.74% .. +27.72%]  overhead    +0.94%
dynamic/access-relative    change  -0.56%  [-11.34% .. +62.71%]  overhead  +251.63%
dynamic/access-contended   change  +5.32%  [ -7.69% .. +628.75%]  overhead    +7.23%

windows

dynamic/launch             change  +0.41%  [-13.04% .. +18.02%]  overhead   +27.90%
dynamic/access             change  -1.07%  [-20.43% ..  +7.71%]  overhead    +3.32%
dynamic/access-relative    change  -2.65%  [-16.46% .. +13.96%]  overhead    +0.00%
dynamic/access-contended   change  +3.09%  [ -6.82% .. +14.94%]  overhead    +5.45%

wan9chi and others added 4 commits October 2, 2026 18:08
prepare_upload returns the upload as an async block that owns what it
needs, in place of the PendingUpload struct and its send method.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Whether an upload is still running when the tasks finish depends on how
fast the remote cache responds, so the steps that upload delayed the
test backend's stores to make the waiting message appear. The delay
only made it likely.

VP_RUN_INTERNAL_HIDE_PENDING_UPLOADS hides the message, and those steps
set it instead. The backend's store delay is removed. pending_uploads
uses stalled-remote-cache, where the uploads never finish, so the
message always appears, and the case now runs on Windows too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It was removed because its upload fails in the background right after
it starts, so whether the message about pending uploads appeared
depended on timing. With VP_RUN_INTERNAL_HIDE_PENDING_UPLOADS hiding
that message, the case is stable again, and a background upload that
fails with a network error is covered again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vtt stalled-remote-cache is back to main's version, without
--fetch-miss. remote-cache-server takes --stall ROUTE instead: the
backend reads requests to the route but never answers them, and emits a
"stalled" milestone when one arrives. The wrapper now leaves Ctrl-C to
the command.

pending_uploads, ctrl_c_during_upload, fast_fail_during_upload, and
hide_pending_uploads use --stall /store, so like the other backend
cases they need Node.js and are skipped on Windows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant