Repository navigation
fix(cli): a cloud upload cut at a fixed age stops early and shows its progress - #7350
Merged
Merged
Conversation
… cuts and shows its progress
Contributor
Fallow audit reportQuality gate failed Found 3 findings. Health (3)
Generated by fallow.
|
Contributor
There was a problem hiding this comment.
Approving at 2e60ba1e. No blockers.
Verified locally (Linux):
- At this head,
src/cloud/upload.test.tsandsrc/commands/cloudpass (64 tests). Acrosssrc/cloudandsrc/commands/cloud, 215 of 216 pass. The one failure isoffload.undecodableTrack.test.ts: my local ffmpeg couldn't build that test's 4-channel PCM.movinput. The diff doesn't touch that test or its code. - The fails without the fix claim holds. With main's
upload.tsswapped in, all three new tests fail:stops after a second identical cut…,reports the bytes sent while a slow PUT runs…andsays how many tries it made…. With the fix restored, they pass.
Code:
- The early stop is conservative enough. It needs two connection-cut failures in a row (
ECONNRESET,EPIPE,ECONNABORTEDor a socket hang up) where the earlier try had sent bytes, and the two tries' age and bytes sent must be within 20% of each other. Stalls, 5xx responses and the fetch path (which reportssent = 0) still take the normal retries. - Final errors are still thrown unwrapped. Only exhausted retries get wrapped, and the wrapper keeps
codeandcause. Nothing downstream checks the error class of retryable failures. - The progress percent is capped at 99 until the upload finishes, and the existing
percent: 100event has nosentBytes, so the reporter skips it. Theev.attempt === undefinedguard keeps the zip's "uploading to S3…" line from being printed again.
Non-blocking notes:
- Behaviour change:
--jsonmode used to print nothing for the zip upload. It now writes JSON progress lines to stderr. The PR describes this and stdout stays clean, but any caller that treats stderr output as a failure would see the new lines. progressReporterkeeps onelastPercentfor all tries. After a restart, the next try therefore reports on the 10 s timer until it gets 5 points past the earlier try's high mark. That still meets "at least every 10 s".
SanHsien
added a commit
to SanHsien/hyperframes
that referenced
this pull request
Nov 7, 2026
…-com#7336-heygen-com#7358 Adopt heygen-com#7304 (without CLI renderDiagnostic, needs heygen-com#6725), heygen-com#7331, heygen-com#7332, heygen-com#7334, heygen-com#7337, heygen-com#7336, heygen-com#7339, heygen-com#7289, heygen-com#5594, heygen-com#6900, heygen-com#7322, heygen-com#7342, heygen-com#7343, heygen-com#7350 (onProgress only), heygen-com#7352, heygen-com#7348, heygen-com#7344, heygen-com#7353, heygen-com#7356 and heygen-com#7355. Defer heygen-com#5708 (needs heygen-com#6911) and heygen-com#7345 (READ_VERSION 4 vs 7); heygen-com#7307 not applicable. Re-read 14 moved pins, pin 6 new PRs (monitored 126). Make checkReportFile module-private and suppress the cross-package closeTestChrome duplicate for fallow. Co-authored-by: Miguel Ángel <miguel.sierra@heygen.com> Co-authored-by: SophiaHuangCc <129631224+SophiaHuangCc@users.noreply.github.com> Co-authored-by: Dante <duanjl.china@gmail.com> Co-authored-by: Muzzy5150 <muzzy5150yt@gmail.com> Co-authored-by: ump45nose <52391318+ump45nose@users.noreply.github.com> Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A cloud upload whose connection is cut at a fixed age no longer repeats the same doomed try four times, and a long upload now says how far it got.
--json({"event":"upload_progress","file","attempt","percent","sent_bytes","total_bytes"}). A second try says it restarted from the first byte.The connection was cut at N s on two tries in a row, after P% of the file was sent ... this link cannot finish it before the cut.Why
Cloud exports were failing in the prepare stage with
Media upload failedafter 26 to 35 minutes. The uploader sends one signed PUT, restarts it from byte 0 on any failure, and tries 1 + 3 times with nothing bounding a try. If anything on the path drops every connection at a fixed age and the link cannot finish the file before it, every try dies at that age: failure time = 4 x age + 7 s of backoff, so 26 to 35 minutes means cuts at about 6.5 to 8.7 minutes. A single large file also printed nothing for the whole PUT, so a live slow upload and a dead one looked the same.Reproduced with the real uploader against a local server that drains 100 KB/s and cuts every connection at 15 s, a 4 MB file: tries 1 to 4 each cut at 15 s after the same 1.5 MB, failure at 67 s (4 x 15 s + 7 s),
read ECONNRESET. Controls: no cut finishes in 41 s; a 1 MB file that fits in 15 s finishes in 10 s. After this change the same run stops after the second cut.How
putWithRetryrecords each try's age and bytes (PutTry), and compares a connection-reset failure with the previous one. The byte count is what the socket has accepted (bytesWritten, sampled by the existing stall watcher), so the last few MB can be buffered ahead of the wire.No overall time limit was added: it would kill valid slow uploads. The progress lines let a caller apply its own no-progress stop. A link that cannot finish a file before a fixed cut needs a resumable or multipart upload, which is a server change and not in this PR.
Size
One root in one module (
upload.ts), its caller wiring and its tests; nothing else touches the uploader.Test plan
cd packages/cli && npx vitest run src/cloud src/commands/cloud: 216 passed, 5 runs in a row; oxlint, oxfmt and tsc clean.upload.ts.upload.ts16.4% to 13.8%,render.ts10.2% to 9.95%,upload.test.ts0.73% to 0.64%.