Repository navigation
Conversation
A pinned runtime download whose response body stops arriving for the 1-minute stall timeout failed the whole update: the stall raised the same TimeoutError as a host that never answers, and isTransientDownloadFailure treats that as fatal. The stall now fails with its own error, which the existing retry schedule (3 more attempts, 2/4/8 s apart) retries like a body that fails after the host answered. No answer at all still fails at once, and the error after the last attempt still reads "(timed out)". Refs pingdotgg#36877 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — Stalled release downloads now retry within the existing bounded retry policy, while unanswered requests still fail without retries. Integrity checks and staged installation remain unchanged, limiting the impact to download recovery and waiting time. You can add or adjust custom eligibility rules. Learn more. |
|
No actionable comments were generated in the recent review. Walkthrough
Merge Risk:
|
Problem
A server update fails as soon as the release download stalls once.
fetchReleaseAsset(cloud.pinned_runtime.fetch_release_asset) applies the 1-minutePINNED_RUNTIME_DOWNLOAD_STALL_TIMEOUTto the response body, but a stall raised the sameCause.TimeoutErroras a host that never answers, andisTransientDownloadFailurereturnsfalsefor everyTimeoutError. SoDOWNLOAD_RETRYnever retried a stall. On a slow link to GitHub release assets, one stall anywhere in the archive download failed the update withPinned runtime install failed while downloading the t3 release archive (timed out)., which is the log in #36877.Change
apps/server/src/cloud/pinnedRuntime.ts: the body stall now fails with its own module-privateReleaseDownloadStalledError, andisTransientDownloadFailuretreats it as transient. This matches how a body that fails after the host answered (DecodeError) is already treated.Effect.timeoutaroundexecute, the rule fix(server): server updates retry when a release download fails briefly #33896 set for a host that cannot reach the release source.DOWNLOAD_RETRYas a 5xx: at most 3 more attempts, 2, 4, then 8 s apart, each with its own stall timeout. There is no separate total-time cap on the download today: [Bug]: Remote server update shows no download progress, caps the whole archive download at 10 minutes, and discards it if the attempt is interrupted #18113 replaced it with the stall timeout, andPINNED_RUNTIME_INSTALL_TIMEOUTonly bounds tar extraction. A host that stalls every attempt now fails after about 4 minutes instead of 1, with the install lock held.... (timed out).ensurePinnedRuntimeInstalledis shared, so remote server updates,t3 updateand the service install all get this.Scope
Refs #36877. This fixes only the first point of that issue: a stall is now transient and retried. Two parts are left:
Range/If-Rangerequest, handling of a 200 that ignores the range, and new tests. That is a second change to the download path, so it belongs in its own PR. With this fix, a link that stalls now and then finishes once one attempt gets through without a stall.net::ERR_TIMED_OUT) is a separate code path, and this PR does not touch it.Verification
End to end, real HTTP. The real
ensurePinnedRuntimeInstalled→fetchReleaseAssetpath ran in Node with:FetchHttpClientlayer thatt3 updateusesProcessRunner, which extracts with System32tar.exe--versionvalidate like the one int3 updateThe release source was a local
http.createServermirror passed asreleaseBaseUrl. Its fixture is a real win32-x64 release zip (39.5 MB,node.exepackaged ast3.exe) with itsSHA256SUMS. The first archive response sends the headers and 1 MiB, then stalls for 75 s. Later requests get the full body. The timeouts are the real ones, with no shortened seam. Windows 11, Node 26.Before, origin/main e101cae: one stall fails the install after a single attempt.
After, this branch: the stall is retried 2 s later and the install completes.
Unit tests in
apps/server/src/cloud/pinnedRuntime.test.ts:PinnedRuntimeInstallError: Pinned runtime install failed while downloading the t3 release archive (timed out)., and passes here.downloading the t3 release checksums (timed out). This pins the side of the rule that must not retry, and it passes on main too.Commands, from
apps/server:pnpm exec vp test run src/cloud/pinnedRuntime.test.ts src/cloud/selfUpdate.test.tssymlinkEPERMon this Windows machine. This change does not touch them.pnpm exec vp run typecheck: passes.vp run check:changed: format, lint, knip 1/2, graphql and typecheck pass.The pre-commit hook could not run in this worktree: its shared
core.hooksPathloses the drive letter under Git Bash. Running itsvp stageddirectly,vp fmtandvp lintpassed on the staged files, butknip:checkran out of memory locally (RangeError: Array buffer allocation failedin oxc-parser). After these manual checks, the commit was made with the hook skipped.Not checked here:
check:changedhit its 900 s limit, and the hook'sknip:checkran out of memory. CI runs it. The change adds no exports.Written by Claude Opus 5.5 in Claude Code via T3 Code.
🤖 Generated with Claude Code