本文目录8 节

页面记住了任务,不代表任务可以恢复

AI 图片和视频通常不是一次请求就返回最终资源。前端先创建本地任务,向服务端提交生成请求,拿到任务标识后再持续查询状态。

为了让用户刷新页面后仍能看到进度,任务列表会写入本地存储。问题也出在这里:有些任务在请求刚发出、服务端还没有返回任务标识时,页面就被刷新了。

重新进入后,前端恢复了这条本地记录。它的状态仍然是“提交中”,界面也继续显示生成动画,但已经没有任何标识可以向服务端查询。

用户看到的是一个永远生成中的任务。真正缺失的不是进度更新,而是恢复这项任务所需的身份。

这里讨论的是刷新后的恢复语义,不是生成结果为什么出错。输入与输出错配的排查过程,我另外整理在《AI 图片与视频任务异常时,怎样建立一条完整证据链》中。

SUBMITTINGPROCESSING 的恢复能力不同

页面上,两种状态都可以显示为“生成中”:

SUBMITTING
  本地任务已创建
  服务端请求尚未返回
  还没有稳定 taskId

PROCESSING
  服务端任务已创建
  已取得 taskId
  可以继续查询进度

如果只保存一个视觉状态枚举,刷新后就无法区分它们的恢复能力。

可恢复任务至少需要两项事实:

  1. 服务端已经接受这次任务;
  2. 前端持有能够继续查询同一任务的稳定标识。

PROCESSING 通常满足这两个条件;没有任务标识的 SUBMITTING 只是一份页面快照。它能证明用户曾经点击过生成,却不能证明服务端是否已经创建任务,更不能证明应该向哪里恢复轮询。

为什么不能自动重新提交

最直接的想法是:既然没有任务标识,就用本地数据再发一次生成请求。

这个方案有几个风险:

  • 原请求可能已经到达服务端,只是响应没有返回前页面被关闭;
  • 本地快照不一定保存完整且仍然有效的请求参数;
  • 自动重放可能创建第二个付费任务;
  • 用户并没有再次确认生成,页面却在恢复时主动产生消耗;
  • 两次任务晚到后,结果和当前选中状态还可能互相覆盖。

因此,无法安全续查不等于可以安全重放。涉及额度或付费资源时,自动重新提交尤其危险。

最终策略更保守:恢复会话时移除没有任务标识的提交中记录;处理中任务只有携带稳定任务标识时才保留并恢复查询。

这会让一条不完整的本地卡片消失,但不会替用户制造一个无法确认是否重复的任务。

清理任务时,还要同步清理选择状态

列表删除无效记录后,页面可能仍然保存着当前选中任务的标识。

如果这项状态没有一起校正,会出现另一类问题:

  • 详情区尝试读取已经不存在的任务;
  • 操作按钮根据旧任务状态继续启用;
  • 新任务进入后仍被旧选择挡住;
  • 页面看起来为空,内部却没有真正回到空状态。

因此恢复流程不是简单过滤数组,还需要重新校验:

恢复本地任务
  -> 删除不可续查记录
    -> 保留终态任务与可查询任务
      -> 检查 selectedTaskId 是否仍存在
        -> 不存在则清理或选择安全默认项

持久化列表和当前选择属于同一份状态契约,不能只修其中一边。

一个 Retry 文案,底层仍然需要多条路径

任务恢复问题也让我重新检查了错误卡片。

从用户视角看,最终结果不可用时只需要一个明确的 Retry 入口;但底层至少有三种不同含义:

  • 生成任务明确失败:重新创建任务;
  • 查询过程临时中断:继续查询原任务;
  • 任务已经完成,但媒体节点加载失败:只重建媒体展示。

如果为了统一界面,把三种情况都处理成“重新生成”,就会让网络波动和媒体错误产生不必要的重复任务。相反,如果让页面同时显示多个技术按钮,用户又需要理解轮询和媒体节点的内部差异。

更合适的方式是统一外层交互,在点击后根据真实错误类型分发到不同恢复动作。统一的是用户看到的入口,不是抹平状态语义。

视觉占位也不能改变任务事实

生成失败后,卡片上半部分可能只剩一块空白。用推荐图片自动填充,看起来可以让页面更完整,却会混淆“失败任务”“推荐素材”和“真实生成结果”。

如果推荐图进入选中状态,页面还可能误以为已经存在可回填的有效结果。

因此失败卡可以增加不参与业务的视觉占位,但它必须满足:

  • 不是生成结果;
  • 不能被选中;
  • 不改变当前任务状态;
  • 不自动启用后续确认操作;
  • Retry 仍然沿用原来的错误恢复语义。

视觉兜底负责减少空白,任务状态仍然只由真实结果决定。

这次验证能够证明什么

这项调整完成了状态恢复逻辑检查、定向静态检查和生产构建;错误卡的单一恢复入口也在浏览器中确认。

为了避免创建付费任务,当时没有专门点击真实 Generate 或可能重新创建任务的 Retry。因此,验证边界需要保留:

  • 可以证明不可恢复的本地记录会在恢复阶段被清理;
  • 可以证明可查询任务仍保留任务标识;
  • 可以证明界面按错误类型分发恢复动作;
  • 不能仅凭构建证明真实生成、额度扣减和服务端轮询全部正常。

持久化异步任务时,我现在会保存什么

以后设计可恢复任务,我会至少检查这些字段:

本地 clientId
服务端 taskId
任务阶段
原始请求的必要摘要
创建时间与用户作用域
最后一次查询状态
错误类型
是否允许安全重试

其中最重要的不是字段数量,而是明确每一种状态在刷新后能做什么。

持久化视觉状态,只能恢复画面;持久化服务端身份,才能恢复同一项异步工作。

Recommended

继续阅读

  1. AI 图片与视频任务异常时,怎样建立一条完整证据链工程笔记 · 9 分钟
  2. 修复 Bug 之后,怎样真正吃透相关代码工程笔记 · 7 分钟