fix: harden install retry with curl pipefail, fast timeouts, and GitHub fallback#67
Conversation
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.
|
@cursor review |
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 93e38bd. Configure here.
|
Thank you ❤️ |
There was a problem hiding this comment.
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
pipefailfor thecurl | bashinstall pipeline socurlfailures return non-zero. - Add a unit test asserting the installer’s
bash -ccommand includesset -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.
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.
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.
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 peerfollowed immediately byvpnot 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
bashran an empty script and exited 0, so the install was reported as successful and the JS retry loop never engaged.Fix
set -o pipefail;so curl's failure propagates as the pipeline's exit code.Connection reset by peer:--connect-timeout 5 --max-time 15irm -TimeoutSec 15https://raw.githubusercontent.com/voidzero-dev/vite-plus/main/packages/cli/install.shhttps://raw.githubusercontent.com/voidzero-dev/vite-plus/main/packages/cli/install.ps1primary → 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 assertionsvp run check:fixcleanvp run buildregeneratesdist/index.mjs