tamakyi
|
c26eb4c648
|
合并任务排队串行,不再互相顶掉进度和杀错 ffmpeg
审查发现:全局只有一份任务进度状态,但没有任何东西拦住两个合并同时跑。
1. 为什么必须串行
jobStart() 原来是无条件重置全部字段的。多个主播同时下播(很常见),
或者自动合并跑着的时候在页面上点一次手动合并,就会有两个任务同时跑:
后启动的把前一个的输出名、进度、已渲染时长全部清零;更糟的是 jobStop()
只认最后注册的那个 ffmpeg,点「停止」杀的是别人家任务的进程,
而自己那个继续跑;两个任务还会互相读到 stopped 标记而提前退出。
界面上看只是一个进度条乱跳,背后是合并结果可能张冠李戴。
2. 怎么串起来的
加一把 mergeSlot 锁占任务位:
- 手动合并用 TryLock,抢不到直接 409 并告诉用户现在谁在跑 —— 它是一次
HTTP 请求,不能让人干等几十分钟。
- 自动合并用 Lock 排队等待,它本来就是后台任务,丢掉白录一场。
jobStart 改成返回 bool:已经有任务在跑时返回 false 且一个字段都不动。
这样即使以后有调用方忘了先拿任务位,也只是失败而不会互相覆盖。
3. 顺带修「panic 之后卡片一直转」
原来 jobFinish() 写在 autoMerge / mergeHandler 的正常返回路径上,任务内部
一旦 panic(外部 safeGo 的 recover 兜在外层)它就永远不会执行,任务会一直
停在 active,界面上的进度条再也不动,ffmpeg 也失联了。
现在统一走 runMergeExclusive():任务位用 defer 释放,panic 翻译成 error,
保证 jobFinish 一定能跑到。
4. 之前 ban 掉的 jobActive() 接回来了
它本来就该是这道护栏,写了却没人调用,现在用于判断要不要提示「在排队」
以及拒绝新任务时报出正在忙的任务名。jobState 的锁改成 RWMutex 供它读。
已验证:
- 新增 4 个用例:TestJobStartRejectsWhenBusy(被拒时 Must 一个字段都不改,
包括进度必须还是原任务的)、TestMergeSlotTryLockExclusive、
TestMergeSlotSerializes(4 个并发任务必须全跑完且不重不漏)、
TestMergeExclusiveReleasesOnPanic(panic 后必须拿到任务位 + 翻出错误)。
- 反向验证:把 jobStart 的占用判断临时改成 `if false && job.active`,
TestJobStartRejectsWhenBusy 立刻报「应当返回 false」。
- 现有测试跟着走真实链路(progress_test 加了 startJobForTest 统一先收尾、
manualmerge_test 走 execManualMerge 独占执行)—— 改之前这些用例单独跑过、
连着跑会失败,正是因为前一个用例把任务状态留在了 active。
- gofmt / go vet / go build / GOOS=linux go build / go test / go test -race 全过。
|
2026-09-26 02:41:29 +08:00 |
|