fix(fs): fsworker always reports phase completion progress

The throttle could drop the final copy heartbeat when it landed inside the
interval (fsproxy.test saw 6291456 instead of 6291461 under ci load). Phase
completion (bytes >= total) is now sent immediately like phase changes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-28 00:56:31 +08:00
1 parent cb3fb9b128
commit 7daf544bd9
1 file changed
+9 -2
+9 -2
View File
@@ -1,5 +1,5 @@
// fsproxy 执行子进程:从 stdin 读一条 JSON 请求,执行单个文件操作,stdout 逐行 JSON 上报
// {t:"hb",phase,bytes,total}(按 progressIntervalMs 节流,阶段切换立即报)/ {t:"ok",result} / {t:"err",code,message}。
// {t:"hb",phase,bytes,total}(按 progressIntervalMs 节流,阶段切换与阶段完成立即报)/ {t:"ok",result} / {t:"err",code,message}。
// SIGTERM → 中止当前操作(copy 会清掉自己的 partial)后退出;挂死在系统调用里时由父进程 SIGKILL 回收。
// 只依赖 node 内置模块,`deno run --no-config` 毫秒级启动。编译二进制可在入口按 --role fsworker 调 fsWorkerMain()。
import { toFsError } from "./errors.ts";
@@ -35,7 +35,14 @@ export async function fsWorkerMain(progressIntervalMs = Number(Deno.env.get("UMT
const progress = (p: FsProgress) => {
const hang = req._test?.hangAfterBytes;
const now = Date.now();
if (p.phase !== lastPhase || now - lastAt >= progressIntervalMs || (hang !== undefined && p.bytes >= hang)) {
// 阶段切换、阶段完成(bytes 到 total)立即报,其余按间隔节流——否则最后一跳可能被节流吞掉
const phaseDone = p.total > 0 && p.bytes >= p.total;
if (
p.phase !== lastPhase ||
phaseDone ||
now - lastAt >= progressIntervalMs ||
(hang !== undefined && p.bytes >= hang)
) {
lastAt = now;
lastPhase = p.phase;
send({ t: "hb", ...p });