
Notes / 工程笔记
一个一直显示“生成中”的任务,为什么不能直接重新提交
从本地任务快照、服务端任务标识和恢复语义出发,复盘异步生成页面刷新后的安全恢复边界。
页面记住了任务,不代表任务可以恢复
AI 图片和视频通常不是一次请求就返回最终资源。前端先创建本地任务,向服务端提交生成请求,拿到任务标识后再持续查询状态。
为了让用户刷新页面后仍能看到进度,任务列表会写入本地存储。问题也出在这里:有些任务在请求刚发出、服务端还没有返回任务标识时,页面就被刷新了。
重新进入后,前端恢复了这条本地记录。它的状态仍然是“提交中”,界面也继续显示生成动画,但已经没有任何标识可以向服务端查询。
用户看到的是一个永远生成中的任务。真正缺失的不是进度更新,而是恢复这项任务所需的身份。
这里讨论的是刷新后的恢复语义,不是生成结果为什么出错。输入与输出错配的排查过程,我另外整理在《AI 图片与视频任务异常时,怎样建立一条完整证据链》中。
SUBMITTING 和 PROCESSING 的恢复能力不同
页面上,两种状态都可以显示为“生成中”:
SUBMITTING
本地任务已创建
服务端请求尚未返回
还没有稳定 taskId
PROCESSING
服务端任务已创建
已取得 taskId
可以继续查询进度
如果只保存一个视觉状态枚举,刷新后就无法区分它们的恢复能力。
可恢复任务至少需要两项事实:
- 服务端已经接受这次任务;
- 前端持有能够继续查询同一任务的稳定标识。
PROCESSING 通常满足这两个条件;没有任务标识的 SUBMITTING 只是一份页面快照。它能证明用户曾经点击过生成,却不能证明服务端是否已经创建任务,更不能证明应该向哪里恢复轮询。
为什么不能自动重新提交
最直接的想法是:既然没有任务标识,就用本地数据再发一次生成请求。
这个方案有几个风险:
- 原请求可能已经到达服务端,只是响应没有返回前页面被关闭;
- 本地快照不一定保存完整且仍然有效的请求参数;
- 自动重放可能创建第二个付费任务;
- 用户并没有再次确认生成,页面却在恢复时主动产生消耗;
- 两次任务晚到后,结果和当前选中状态还可能互相覆盖。
因此,无法安全续查不等于可以安全重放。涉及额度或付费资源时,自动重新提交尤其危险。
最终策略更保守:恢复会话时移除没有任务标识的提交中记录;处理中任务只有携带稳定任务标识时才保留并恢复查询。
这会让一条不完整的本地卡片消失,但不会替用户制造一个无法确认是否重复的任务。
清理任务时,还要同步清理选择状态
列表删除无效记录后,页面可能仍然保存着当前选中任务的标识。
如果这项状态没有一起校正,会出现另一类问题:
- 详情区尝试读取已经不存在的任务;
- 操作按钮根据旧任务状态继续启用;
- 新任务进入后仍被旧选择挡住;
- 页面看起来为空,内部却没有真正回到空状态。
因此恢复流程不是简单过滤数组,还需要重新校验:
恢复本地任务
-> 删除不可续查记录
-> 保留终态任务与可查询任务
-> 检查 selectedTaskId 是否仍存在
-> 不存在则清理或选择安全默认项
持久化列表和当前选择属于同一份状态契约,不能只修其中一边。
一个 Retry 文案,底层仍然需要多条路径
任务恢复问题也让我重新检查了错误卡片。
从用户视角看,最终结果不可用时只需要一个明确的 Retry 入口;但底层至少有三种不同含义:
- 生成任务明确失败:重新创建任务;
- 查询过程临时中断:继续查询原任务;
- 任务已经完成,但媒体节点加载失败:只重建媒体展示。
如果为了统一界面,把三种情况都处理成“重新生成”,就会让网络波动和媒体错误产生不必要的重复任务。相反,如果让页面同时显示多个技术按钮,用户又需要理解轮询和媒体节点的内部差异。
更合适的方式是统一外层交互,在点击后根据真实错误类型分发到不同恢复动作。统一的是用户看到的入口,不是抹平状态语义。
视觉占位也不能改变任务事实
生成失败后,卡片上半部分可能只剩一块空白。用推荐图片自动填充,看起来可以让页面更完整,却会混淆“失败任务”“推荐素材”和“真实生成结果”。
如果推荐图进入选中状态,页面还可能误以为已经存在可回填的有效结果。
因此失败卡可以增加不参与业务的视觉占位,但它必须满足:
- 不是生成结果;
- 不能被选中;
- 不改变当前任务状态;
- 不自动启用后续确认操作;
- Retry 仍然沿用原来的错误恢复语义。
视觉兜底负责减少空白,任务状态仍然只由真实结果决定。
这次验证能够证明什么
这项调整完成了状态恢复逻辑检查、定向静态检查和生产构建;错误卡的单一恢复入口也在浏览器中确认。
为了避免创建付费任务,当时没有专门点击真实 Generate 或可能重新创建任务的 Retry。因此,验证边界需要保留:
- 可以证明不可恢复的本地记录会在恢复阶段被清理;
- 可以证明可查询任务仍保留任务标识;
- 可以证明界面按错误类型分发恢复动作;
- 不能仅凭构建证明真实生成、额度扣减和服务端轮询全部正常。
持久化异步任务时,我现在会保存什么
以后设计可恢复任务,我会至少检查这些字段:
本地 clientId
服务端 taskId
任务阶段
原始请求的必要摘要
创建时间与用户作用域
最后一次查询状态
错误类型
是否允许安全重试
其中最重要的不是字段数量,而是明确每一种状态在刷新后能做什么。
持久化视觉状态,只能恢复画面;持久化服务端身份,才能恢复同一项异步工作。
Recommended