fix: 拒绝环形 DAG 并避免无效工作流堵塞任务队列
This commit is contained in:
+28
-5
@@ -11,11 +11,11 @@
|
||||
| R01 | P0 | 普通删除接口可能删除批量源视频目录;清理逻辑从输入路径推导删除范围 | 已修复 | 普通接口拒绝单独删除批量 run;手动与自动清理只删除该上传任务的私有目录;视频、旁挂字幕及其他任务文件不受影响 |
|
||||
| R02 | P1 | 自适应线程池限流后可能扩容;退出标记位于积压队列尾部,缩容不及时 | 已修复 | 限流不增加并发;降低目标后不再超额提交;真实积压队列验证 |
|
||||
| R03 | P1 | 最后节点执行时暂停再继续会覆盖有效下载 URI;批量缺产物仍清理并完成 | 已修复 | 收尾幂等,恢复后全部必需产物可下载;缺产物不清理工作空间 |
|
||||
| R04 | P1 | 环形 DAG 可通过保存校验,执行失败后仍在 QUEUED 堵塞队列 | 待处理 | 保存/发布拒绝无效 DAG;历史无效任务进入 FAILED,不阻塞后续任务 |
|
||||
| R05 | P1 | 翻译按固定四行解析 SRT;补齐行数不能保证文本与时间轴对应 | 待处理 | 合法多行 cue 正确解析;按稳定 ID 回填译文并校验缺失、重复项 |
|
||||
| R06 | P1 | OCR 跨空白帧合并相同字幕;临时请求失败被永久存为无文字 | 待处理 | 空白帧结束当前字幕段;无文字和可重试失败分开存档 |
|
||||
| R04 | P1 | 环形 DAG 可通过保存校验,执行失败后仍在 QUEUED 堵塞队列 | 已修复 | 保存/发布拒绝无效 DAG;历史无效任务进入 FAILED,不阻塞后续任务 |
|
||||
| R05 | P1 | 翻译按固定四行解析 SRT;补齐行数不能保证文本与时间轴对应 | 已修复 | 合法多行 cue 正确解析;按稳定 ID 回填译文并校验缺失、重复项 |
|
||||
| R06 | P1 | OCR 跨空白帧合并相同字幕;临时请求失败被永久存为无文字 | 已修复 | 空白帧结束当前字幕段;无文字和可重试失败分开存档 |
|
||||
| R07 | P2 | 抽帧/分块目录残留污染重跑;OCR/过滤存档无输入和参数指纹 | 待处理 | 输出减少时无旧文件混入;输入/有效参数变化时断点失效 |
|
||||
| R08 | P2 | 批量任务未固定工作流版本,恢复收尾可能使用新版本定义;创建任务与明细不原子 | 待处理 | 执行与收尾使用固定版本;工作线程只看到完整的已创建任务 |
|
||||
| R08 | P2 | 批量任务创建与明细不原子;不区分工作流版本时的执行/收尾一致性 | 待处理(方案调整) | 用户决定不区分工作流版本,不实施固定版本方案;工作线程只看到完整任务,收尾使用本次执行实际产物 |
|
||||
|
||||
## 优化与维护清单
|
||||
|
||||
@@ -69,7 +69,30 @@
|
||||
- 相关回归:`uv run pytest tests/test_finalization.py tests/test_scheduler.py tests/test_batch.py tests/test_apps_api.py tests/test_db.py -q --tb=short`,97 passed,3.22 秒。
|
||||
- 补充批量复制故障及安全回归:`uv run pytest tests/test_finalization.py tests/test_maintenance.py tests/test_run_deletion_safety.py -q --tb=short`,22 passed,5.83 秒。真实视频/字幕验证写满故障后旧成品和工作空间完整,故障解除可成功放置并清理;API 下载验证原始文件与两个最终别名均可读取。仅有既存 Starlette/httpx 弃用警告。
|
||||
- 状态:修复及验证完成,纳入 `fix/review-improvements` 分支;未部署。原子性为单文件级,多文件中途失败允许部分完整成品已经更新,重试会重新放置;不承诺断电持久性。
|
||||
- 剩余边界:批量固定工作流版本仍由 R08 跟踪;此修复不会自动重建已经丢失的历史成品。
|
||||
- 剩余边界:R08 按用户决定调整为不区分工作流版本,固定版本方案取消;版本机制调整及任务原子创建另行实施。此修复不会自动重建已经丢失的历史成品。
|
||||
|
||||
## R05 / R06 修复记录
|
||||
|
||||
- 顺序:按用户要求先完成 R05,再完成 R06;R03 已提交为 `3a61291`。
|
||||
- R05:新增 `nodes/srt.py` 按 cue 解析 BOM/CRLF、多行及空正文,坏字幕明确报错;翻译以全局位置 ID 的 JSON 条目请求,校验 ID 集合、类型、唯一性及正文。乱序按 ID 回填,结构错误最多尝试 3 次,耗尽 failed,取消末尾合并/补空策略。空 cue 保留时间轴且不请求模型,原有幻觉清洗继续执行。
|
||||
- R05 TDD:12 个新回归用例先失败;相关节点/清洗/专名/翻译测试 93 passed、1 skipped、18 deselected(排除 Whisper)。最后调整提示词统一“条目”措辞后翻译对齐测试 13 passed(含真实短句 LLM 校准),0.76 秒。
|
||||
- R06:空帧终止当前字幕段;失败/异常不写成功存档,失败帧在收紧的并发下重试一次,仍失败则节点 failed,已成功帧断点保留。新存档 status=completed 表示成功(含无文字),status=skipped 表示超长输出按既有规则跳过。
|
||||
- 旧存档兼容:非空结果继续复用,无状态旧空串因无法区分超时与无文字而重新 OCR;不自动重跑已完成的历史任务。
|
||||
- R06 TDD:4 个新回归先失败,覆盖跨空帧合并、failed 响应、抛异常和旧空串恢复。全量数据修正后 1942 条,旧 1666 条文件未修改;测试比较真实单线程、4/16 线程与断点结果,并逐采样点检查字幕不跨空白。基线必须走完整节点路径(包含超长过滤),不以原始 OCR 文本冒充成功存档。
|
||||
- 最终组合验证:`uv run pytest tests/test_ocr_recovery.py tests/test_ocr_flow.py tests/test_subtitle_ocr_order_threading.py tests/test_integration_subtitle_ocr.py tests/test_translation_line_alignment.py tests/test_hallucination_mask.py tests/test_proper_nouns.py -q --tb=short --show-capture=no`,71 passed、1 skipped,58.69 秒;跳过项缺少历史专名素材,真实 LLM 与真实 OCR 集成通过。`git diff --check` 通过。
|
||||
- 状态:R05/R06 工作区已修复,尚未提交、未部署。模型语义是否正确仍需内容质量评估,ID 校验保证程序不会因列表乱序或漏项贴错时间。
|
||||
- R08 决策:用户计划不区分工作流版本,取消固定版本修复方案;版本机制调整、执行/收尾一致性及批量原子创建保留待办,本轮未实施数据库迁移。
|
||||
|
||||
## R04 修复记录
|
||||
|
||||
- 根因:①保存路径只做结构校验(`WorkflowDefinition.validate()`:名称/版本/节点 ID 唯一/边引用存在),环形依赖结构合法因而被写库并发布;②`execute_run` 的 DAG 解析、校验与拓扑排序在 `try` 块**之外**,环检测抛出的异常直接冒到 `_loop` 被吞掉,任务状态从未离开 QUEUED——`next_queued_run` 每轮拾起同一条队首记录,后续任务永久堵塞。
|
||||
- 修复 1(保存/发布):[routers/workflows.py](../src/wov_app/routers/workflows.py) 的 `_validate_definition` 在校验后调用 `topological_sort`,环形 DAG(含自环)以 "workflow contains a cycle" 转 422;创建/校验/发布三个入口共用该函数,`publish` 额外重新校验最新版本定义,历史遗留的环形版本无法进入应用中心。校验先于任何写库,被拒请求不产生工作流或版本记录。
|
||||
- 修复 2(历史无效任务):[scheduler.py](../src/wov_app/scheduler.py) 把 `from_dict` / `validate` / `topological_sort` 移入 try,任何预检异常都立刻把 run 置 FAILED 并记录错误后返回,队首随即前移,不再堵塞后续任务。
|
||||
- 方案边界:环检测放在**入口校验**(保存/发布)而非 `WorkflowDefinition.validate()`,因此 `WorkflowDefinition.validate()` 保持只做结构校验、SDK 协议模型不变;批量任务在工作流级校验仍放行环形定义,由调度器把每个视频的 run 判 FAILED(保留既有"单视频失败不中断整批"语义,`test_batch_worker_cycle_fails_video_not_job` 未改动仍通过)。批量的 run 现在由调度器直接置 FAILED 并回填错误,不再依赖异常冒泡。
|
||||
- TDD 红:新增 5 个回归用例先失败——创建带环工作流返回 200、校验接口返回 200、发布历史环形版本返回 200、环形任务执行后仍停在 QUEUED(队首堵塞)、缺 name 的非法定义同样卡住队列。
|
||||
- TDD 绿及相关回归:`uv run pytest tests/test_workflow_api.py tests/test_scheduler.py -q`,29 passed,1.07 秒;`uv run pytest tests/test_batch.py tests/test_apps_api.py tests/test_seed.py tests/test_models.py tests/test_registry.py tests/test_api.py tests/test_finalization.py -q`,95 passed,2.59 秒。
|
||||
- 全量回归:`uv run pytest -q`,402 passed、5 skipped,84.03 秒;仅既存 Starlette/httpx 弃用警告。`git diff --check` 通过。
|
||||
- 状态:修复及验证完成,纳入 `fix/review-improvements` 分支工作区(与 R05/R06 未提交改动共存);未部署。历史遗留的环形已发布工作流不会被自动取消发布,仍可创建任务,但任务会立即 FAILED 且不堵塞队列;如需清理线上遗留数据需另行确认后执行。
|
||||
|
||||
## 审查基线
|
||||
|
||||
|
||||
Reference in New Issue
Block a user