Skip to content

fix: harden install retry with curl pipefail, fast timeouts, and GitHub fallback#67

Merged
fengmk2 merged 5 commits into
mainfrom
fix/install-pipefail
May 10, 2026
Merged

fix: harden install retry with curl pipefail, fast timeouts, and GitHub fallback#67
fengmk2 merged 5 commits into
mainfrom
fix/install-pipefail

Conversation

@fengmk2
Copy link
Copy Markdown
Member

@fengmk2 fengmk2 commented May 10, 2026

Summary

The install step (curl -fsSL https://viteplus.dev/install.sh | bash) was failing on transient network errors with no recovery — even though there was a retry loop in code, it never fired. Two CI runs hit it in the same window:

Both showed curl: (35) Recv failure: Connection reset by peer followed immediately by vp not being on PATH — no retry attempted.

Root cause

A shell pipeline returns the exit code of the last command. When curl failed, it produced no output, the trailing bash ran an empty script and exited 0, so the install was reported as successful and the JS retry loop never engaged.

Fix

  1. Pipefail. Prepend set -o pipefail; so curl's failure propagates as the pipeline's exit code.
  2. Fast per-call timeouts. Cap each network call at 15s so hung connections fail fast instead of stalling ~30s on Connection reset by peer:
    • bash: --connect-timeout 5 --max-time 15
    • pwsh: irm -TimeoutSec 15
  3. GitHub fallback URL. When the CDN is unhealthy, fall back to the install scripts in the vite-plus repo:
    • https://raw.githubusercontent.com/voidzero-dev/vite-plus/main/packages/cli/install.sh
    • https://raw.githubusercontent.com/voidzero-dev/vite-plus/main/packages/cli/install.ps1
  4. Alternate URLs each attempt. Order is primary → fallback → primary → fallback (2 rounds × 2 URLs = 4 attempts max). A single primary failure flips to the mirror immediately instead of burning more retries on the same broken URL.

Worst-case budget: ~66s (4 × 15s + 3 × 2s back-off), vs the original ~96s budget that gave up before the upstream blip cleared.

Test plan

  • vp run test — install-viteplus tests pass, including new fallback / alternation / pipefail assertions
  • vp run check:fix clean
  • vp run build regenerates dist/index.mjs

The install command `curl -fsSL <url> | bash` masked curl's exit code
because a shell pipeline returns the last command's status by default.
When curl hit a transient network error (e.g. "Recv failure: Connection
reset by peer"), it produced no output, the trailing `bash` ran an empty
script and exited 0, so the install was reported as successful and the
retry loop never fired. Subsequent `vp` invocations then failed with
"Unable to locate executable file: vp".

Prepend `set -o pipefail` so curl's non-zero exit propagates and the
existing retry/back-off in installVitePlus actually engages.
@fengmk2 fengmk2 self-assigned this May 10, 2026
Copilot AI review requested due to automatic review settings May 10, 2026 14:23
@fengmk2
Copy link
Copy Markdown
Member Author

fengmk2 commented May 10, 2026

@cursor review

Copy link
Copy Markdown

@cursor cursor Bot left a comment

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 93e38bd. Configure here.

@liangmiQwQ
Copy link
Copy Markdown

Thank you ❤️

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a reliability issue in the Vite+ installer where curl -fsSL <url> | bash could mask transient curl failures (because the pipeline exit status defaults to the last command). By enabling pipefail in the bash -c invocation, curl errors correctly propagate and the existing retry/backoff logic in installVitePlus can engage.

Changes:

  • Enable pipefail for the curl | bash install pipeline so curl failures return non-zero.
  • Add a unit test asserting the installer’s bash -c command includes set -o pipefail.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated no comments.

File Description
src/install-viteplus.ts Prepends set -o pipefail to the `curl
src/install-viteplus.test.ts Adds a regression test verifying the bash -c invocation includes pipefail.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

fengmk2 added 2 commits May 10, 2026 22:30
The pipefail change unmasked curl failures, but a 96s budget across
three short back-offs (2s, 4s) wasn't enough to outlast a brief upstream
blip — all attempts hit the same `curl: (35) Recv failure` and the
action gave up.

Layer the retries:

- Inner: curl `--retry 3 --retry-delay 5 --retry-all-errors` plus
  `--connect-timeout 10 --max-time 60`. Handles transient connection
  resets (incl. TLS handshake) within a single outer attempt without
  burning one. PowerShell gets the equivalent
  `-MaximumRetryCount 3 -RetryIntervalSec 5` on Invoke-RestMethod.
- Outer: bump max attempts from 3 to 5 with exponential-ish back-off
  (5s, 15s, 30s, 60s) for ~2 minutes of total wait, on top of curl's
  own retries.
Drop the long exponential back-off (5/15/30/60s) and revert to the
short 3-attempt linear back-off (2s, 4s). Instead of waiting longer
on the same upstream, fall back to the install scripts in the
vite-plus repo when the CDN has exhausted its retries:

- https://raw.githubusercontent.com/voidzero-dev/vite-plus/main/packages/cli/install.sh
- https://raw.githubusercontent.com/voidzero-dev/vite-plus/main/packages/cli/install.ps1

Also drop curl's --retry/--retry-all-errors and just keep the timeout
caps (--connect-timeout 5 --max-time 30) so each curl call fails fast
and the outer retry can move on. Total worst-case budget is now
2 URLs * (3 * 30s + 2s + 4s) = ~3 minutes vs ~10+ minutes before.
Copilot AI review requested due to automatic review settings May 10, 2026 14:41
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 3 changed files in this pull request and generated 4 comments.

Comment thread src/install-viteplus.ts Outdated
Comment thread src/install-viteplus.ts Outdated
Comment thread src/install-viteplus.test.ts
Comment thread src/install-viteplus.test.ts
Switch from "3x primary then 3x fallback" to "primary, fallback,
primary, fallback" — 2 rounds × 2 URLs = 4 attempts max. A single
upstream failure now flips to the GitHub mirror immediately instead
of burning two more retries on the same broken URL.

Also tighten per-call timeouts so a hung connection fails in 15s
instead of 30s:
- bash:  --connect-timeout 5 --max-time 15
- pwsh:  irm -TimeoutSec 15

Worst-case total: 4 × 15s + 3 × 2s = ~66s, vs ~3 minutes before.
@fengmk2 fengmk2 changed the title fix: propagate curl failure in install script via pipefail fix: harden install retry with curl pipefail, fast timeouts, and GitHub fallback May 10, 2026
@fengmk2 fengmk2 merged commit ca1c466 into main May 10, 2026
80 checks passed
@fengmk2 fengmk2 deleted the fix/install-pipefail branch May 10, 2026 15:04
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.

3 participants