Skip to content

cli: reuse a fully-staged server download after an interrupted update - #331752

Open
srikanthananthula (srikanthananthula63053) wants to merge 1 commit into
microsoft:mainfrom
srikanthananthula63053:fix-331690-reuse-staged-server-download
Open

cli: reuse a fully-staged server download after an interrupted update#331752
srikanthananthula (srikanthananthula63053) wants to merge 1 commit into
microsoft:mainfrom
srikanthananthula63053:fix-331690-reuse-staged-server-download

Conversation

@srikanthananthula63053

@srikanthananthula63053 srikanthananthula (srikanthananthula63053) commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #331690.

DownloadCache::create() (used by the Rust CLI's server/CLI installer at cli/src/tunnels/code_server.rs, cli/src/commands/serve_web.rs, and cli/src/tunnels/agent_host.rs) unconditionally deleted its .staging directory before every download. If the process was killed after a download+extract fully finished populating .staging but before the atomic rename into the final commit-keyed directory (e.g. VS Code closed right as a server update finished downloading), the next launch discarded that already-complete download and re-fetched it from update.code.visualstudio.com, wasting bandwidth on a patch that was already available locally — exactly the scenario described in the issue.

Root cause

In DownloadCache::create():

  1. Download happens into a sibling <name>.staging directory.
  2. On success, <name>.staging is renamed into the final <name> directory.
  3. On the next call, if <name> doesn't exist yet, any leftover <name>.staging was unconditionally wiped before starting a fresh download — with no way to tell "this is a partial download from a connection failure" apart from "this is a complete download that just never got renamed because the process was killed a moment too early".

Fix

Write a small completion marker file (.complete) into the staging directory immediately after the do_create closure (the download+extract+verify logic) succeeds, before attempting the rename. On the next create() call:

  • If the marker is present, the staged content is known-complete from a prior run — skip do_create entirely and go straight to the rename, avoiding any network request.
  • If the marker is absent, the staging directory (if any) is a partial/corrupt leftover as before, and is wiped before a fresh download.

The marker is stripped from the final directory after a successful rename, so callers that enumerate the returned directory (e.g. the CLI-binary installer, which picks the first entry via read_dir) never see it.

This is fully contained in DownloadCache — none of its 4 call sites needed to change.

Test plan

  • Added cli/src/download_cache.rs unit tests:
    • test_existing_valid_target_is_reused_without_download — an already-installed commit is returned without invoking do_create.
    • test_missing_patch_triggers_download — nothing cached → do_create runs and its output lands at the final path.
    • test_incomplete_staging_download_triggers_fresh_download — a staging dir without the completion marker (simulating a connection drop mid-download) is discarded and do_create runs again, with stale partial content not surviving into the result.
    • test_interrupted_update_restart_reuses_completed_staging_without_redownload — the core regression test: a staging dir with the completion marker (simulating a kill right before the final rename) is reused with do_create never invoked, and the marker itself doesn't leak into the final directory.

Fixes microsoft#331690

DownloadCache::create() unconditionally deleted its .staging directory
before every download. If the process was killed after a download+
extract finished populating .staging but before the atomic rename into
the final commit-keyed directory (e.g. VS Code closed right as a
server update finished), the next launch discarded that already-valid
download and re-fetched it from the update service, wasting bandwidth
on a patch that was already available locally.

Write a completion marker into the staging directory right after the
do_create closure succeeds, before the rename is attempted. On the
next call, a marker's presence means the staged content is already
complete and can be renamed into place directly instead of being wiped
and re-downloaded; a staging directory without the marker is still
treated as partial and discarded, unchanged from before. The marker is
stripped from the final directory after rename so callers that
enumerate it don't see it. No call site of create() needed to change.
Copilot AI balanced review requested due to automatic review settings August 20, 2026 05:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds resumable finalization for completed CLI/server downloads interrupted before staging is renamed.

Changes:

  • Adds a staging completion marker.
  • Reuses completed staging directories.
  • Adds cache recovery unit tests.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread cli/src/download_cache.rs
// The marker is staging-only bookkeeping; strip it from the final
// location so callers that enumerate the returned directory (e.g.
// looking for the single extracted CLI binary) don't see it.
let _ = std::fs::remove_file(target_dir.join(STAGING_COMPLETE_MARKER));
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.

VScode update redownloading patch

3 participants