fix(client-bake): 第一帧判黑后先重试,别把能自愈的状况变成整单报废 - #925
Conversation
1024XEngineer#918 加的亮度闸把黑帧拦住了,但 compileAsync 那道预热在真实浏览器里不够 —— 它只保证着色器编译与**已解码**贴图的上传,不等图片本身解码。线上实测 4 单 (886/888/890/891)全部卡在第 0 帧,用户从「悄悄拿到一张黑帧」变成「整单失败」。 改成判黑后每 300ms 重渲一次、最多 10 次;3 秒内没好才失败。贴图解码是几百毫秒 的事,给到 3 秒是十倍余量。 Closes 1024XEngineer#924
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## main #925 +/- ##
==========================================
+ Coverage 86.12% 91.27% +5.14%
==========================================
Files 306 193 -113
Lines 24037 13204 -10833
Branches 3646 0 -3646
==========================================
- Hits 20703 12052 -8651
+ Misses 2360 1152 -1208
+ Partials 974 0 -974
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
The retry behavior addresses transient black frames, but the new awaited retry path needs to preserve the existing cancellation contract before it can be considered safe.
Verification: git diff --check passes. The focused Vitest command could not run in this workspace because frontend dependencies are not installed (vitest: Permission denied).
| // 再渲一次就好了。直接失败等于把一个几百毫秒能自愈的状况变成整单报废。 | ||
| let luma = stage.subjectLuma() | ||
| for (let k = 0; luma >= 0 && luma < MIN_SUBJECT_LUMA && k < BLACK_FRAME_RETRIES; k++) { | ||
| await sleep(BLACK_FRAME_WAIT_MS) |
There was a problem hiding this comment.
[P1] Recheck cancellation during black-frame waits
If signal is aborted while this sleep is pending, the loop resumes and calls subjectLuma() without invoking throwIfAborted(). A still-black frame then throws StageError, which the catch block reports through failBake; if the frame recovers, the code can upload a frame after cancellation. This breaks the existing BakeAborted contract (cancellation must not be reported as failure) for the new retry path. Recheck the signal after the await (or make the wait abort-aware) before sampling or continuing.
Closes #924
问题
#918 加的亮度闸开始拦真实任务。线上连续 4 单失败(886 / 888 / 890 / 891):
闸拦对了,但用户从「悄悄拿到一张黑帧」变成「整单做不出来」——代价太大。
根因
#918 的
compileAsync预热保证的是着色器编译与已解码贴图的上传,不等图片本身 decode。FBXLoader.loadAsync()resolve 之后内嵌贴图仍在异步解码,所以第 0 帧照样黑。为什么用重试
这是个纯等待问题:再渲一次就好了。要精确等到贴图就绪,得逐个 texture 去 await decode,而 three 的贴图来源有 ImageBitmap / HTMLImageElement / CanvasTexture 好几种,覆盖不全仍会漏。
判黑后重渲对所有成因都有效(贴图未解码、着色器未编译、材质异步替换),不需要预测时序。
判黑后每 300ms 重渲、最多 10 次;3 秒没好才失败。
compileAsync保留——它仍消掉一部分情况。验证
前端 format / lint / typecheck / 1382 passed / build 全过。
两个变异方向都红:不重试直接失败(现在线上的行为)、永远不判黑(加闸之前的行为)。
口径更正
#918 里我说「渲第一帧前先 compileAsync 就能解决」,被线上证伪。当时只在自己的探针里验过——探针能过是因为它的贴图更小、解码更快,我没有在真实 BakeStage 里验。