后台任务状态机:让排队、取消和重试可解释

后台任务只有“进行中”和“完成”两个状态时,操作者很难判断它是在等待资源、正在计算,还是已经失败却没有更新界面。更清楚的状态机,能让恢复和交互使用同一套语言。

本篇目标: 为一个虚构的图片处理任务定义状态与转换,分开任务身份和执行尝试。

让每个状态有明确含义
让每个状态有明确含义放大图解 ↗

先写出每个状态的进入条件

queued 表示已接受但尚未开始;running 表示某次尝试获得了执行资格;succeeded 表示结果已经保存并可读取;failed 表示本轮无法继续;cancelled 则需要说明任务已经停止到哪个边界。

状态名本身不重要,进入条件必须明确。例如结果文件还未持久化,就不应先把界面改成成功。

任务 ID 与尝试 ID 分开

同一任务可以有多次尝试,但每次尝试都需要能够被区分。工作者提交结果时,服务器应确认它仍属于当前有效尝试,避免旧工作者的迟到结果覆盖新状态。

{
  "jobId": "demo-job",
  "attemptId": "attempt-b",
  "state": "running",
  "cancelRequested": false
}

这些标识是演示值。实际系统还需要校验领取资格、租约或版本,以及结果保存的原子性。

取消是一段过程

请求取消不一定能立刻中断底层操作。可以先记录取消意图,再由执行者在安全边界检查。已经发送给外部系统的动作,也不会因为状态改成 cancelled 就自动撤回。

界面应告诉用户正在取消、已经停止或无法撤销,避免用同一个“已取消”覆盖不同事实。

把转换写成可检查的表

可以先列出允许的边:queued 到 running、running 到成功或失败、可恢复失败到再次排队。终态回到执行态是否允许,应通过明确的新命令或新运行记录完成。

测试不仅检查正常成功,还要让旧尝试晚于新尝试返回、在保存结果前退出、在取消后收到成功回调、重复处理同一结果。恢复后保留错误原因和已完成阶段,操作者才有依据决定继续、重试或终止。

见字如晤

图解