Ghost Downloader

任务系统

状态机规则与调度机制。

架构总览描述了任务的完整生命周期。这一页深入状态机的内部运作。

源码:app/services/task_service.pyapp/models/task.py

状态派生

任务的状态不是直接设置的值,而是从所有步骤的状态聚合而来。

任务状态机

转换触发
→ 等待入队、恢复保存的任务、重新开始
等待 → 运行调度器分配到异步线程
运行 → 完成所有步骤执行完毕
运行 → 失败任意步骤永久错误
运行 → 已暂停用户暂停
已暂停 / 失败 → 等待用户重新开始
完成 → 等待已完成任务勾选了新的未完成文件

派生规则(按优先级):任一步骤失败 → 失败。全部完成 → 完成。任一运行 → 运行。全部已暂停 → 已暂停。其余 → 等待。

设置任务状态时,先把状态推到所有未完成的步骤,再从步骤重新派生。直接写任务的状态字段无效,下一次步骤状态变更时会被覆盖。

一个三步任务(下载视频 → 下载音频 → 混流),第二步失败时:第一步已完成(保持完成),第二步失败,第三步还在等待。派生结果 → 失败。用户重新开始时,第一步跳过,第二步进度清零重新执行。

步骤迭代

执行时按步骤序号顺序迭代。迭代器在取下一个步骤前重新检查任务状态。如果上一个步骤失败导致任务状态变为失败,迭代立即终止。这是单一错误边界:任何步骤的失败都阻止后续步骤执行。

已完成和未勾选的步骤跳过,只执行处于等待状态的步骤。

取消(暂停)与失败的异常路径不同。取消通过 CancelledError 传播,步骤内部捕获后标记为已暂停;失败通过 TaskError 传播,步骤内部捕获后标记为失败并记录错误信息。两种异常最终都会中止步骤迭代,但对后续恢复行为的影响不同:已暂停的步骤从断点继续,失败的步骤从头执行。

调度

等待队列是一个有序列表。调度器循环检查:运行中的任务数 < 最大并发数时,从队列头部取出任务提交到异步线程。

用户调整最大并发数时,如果运行中的任务数超出新上限,多余的任务会被取消回到等待队列,只取消支持暂停的步骤。不支持暂停的步骤(如 FFmpeg 混流)会继续运行直到完成。

操作链路

所有变更操作的核心模式:取消运行 → 回调 → 后续动作。回调时序取决于任务是否在运行,这是异步桥接的必然结果,详见架构总览

操作取消后做什么
重新下载删除输出文件和进度文件 → 重置所有步骤为等待 → 重新调度
编辑可选删除文件 → 替换参数(URL / 步骤 / 文件大小,任务 ID 不变)→ 应用新选项 → 重新调度
勾选变更更新勾选列表 → 如果已完成任务新增了未完成文件:重新调度
删除可选删除输出文件 → 从内存和持久化中移除

本页目录