From 327ca9c11c5808df757dcf1f3163d63bab20cca8 Mon Sep 17 00:00:00 2001 From: hzw Date: Sat, 12 Sep 2026 20:48:02 +0800 Subject: [PATCH] =?UTF-8?q?docs(video):=20=E5=BC=82=E6=AD=A5=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=20-=20=E7=BB=9F=E4=B8=80=E8=BD=AE=E8=AF=A2=E5=AE=B9?= =?UTF-8?q?=E9=94=99=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...2026-09-12-unified-video-polling-design.md | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 docs/superpowers/specs/2026-09-12-unified-video-polling-design.md diff --git a/docs/superpowers/specs/2026-09-12-unified-video-polling-design.md b/docs/superpowers/specs/2026-09-12-unified-video-polling-design.md new file mode 100644 index 000000000..81b986c70 --- /dev/null +++ b/docs/superpowers/specs/2026-09-12-unified-video-polling-design.md @@ -0,0 +1,109 @@ +# 统一异步视频轮询容错设计 + +## 背景 + +当前异步视频渠道分别在声明式协议和多个内置协议中维护轮询循环。轮询间隔分散为 2.5 秒、3 秒、5 秒、10 秒或 20 秒;除少数协议外,一次 HTTP 502、429、网络超时或连接中断就会结束执行,使本地任务失败并退款,而上游任务可能仍在继续并最终成功。 + +本改动面向开源宿主整体修复,不识别任何供应商、域名或私有模型。 + +## 目标 + +- 所有异步视频协议统一每 30 秒轮询一次,声明式插件和内置协议行为一致。 +- 创建成功后等待 30 秒再首次查询,避免刚创建即查询。 +- 单次可恢复查询异常不得终止整个生成任务。 +- 只在上游明确返回终态失败、遇到确定不可恢复错误或达到任务总超时时结束任务。 +- 成品已生成后,临时下载异常不得立即丢失任务结果。 +- 保留现有任务 ID、计费、审计、渠道并发、熔断和人工恢复边界。 + +## 非目标 + +- 不改变各供应商的请求字段、状态映射或结果结构。 +- 不为单独渠道增加判断或插件私有配置。 +- 不将轮询改造成释放 worker 的持久化后台状态机;该方向可作为后续独立重构。 +- 不自动重试创建请求,避免在缺少供应商幂等保证时重复创建计费任务。 + +## 统一轮询执行器 + +在 `backend/internal/app` 增加宿主级视频轮询执行器。所有异步视频实现通过回调完成一次查询和供应商特有的状态解析,执行器负责等待、错误分类、重试、超时和通用日志。 + +执行流程: + +1. 创建请求成功并取得供应商任务 ID。 +2. 等待 30 秒。 +3. 执行一次查询。 +4. 查询返回处理中时,再等待 30 秒。 +5. 查询遇到可恢复异常时记录重试信息,等待统一间隔或更长的 `Retry-After` 后继续。 +6. 查询成功后清零连续异常计数。 +7. 收到成功或明确失败终态时退出。 +8. 上下文截止时按视频任务超时处理。 + +恢复一个已有供应商任务 ID 时也遵守同一轮询节奏,避免 worker 重启后形成突发查询。 + +## 错误分类 + +以下只适用于已经取得供应商任务 ID 后的查询或结果下载阶段: + +### 可恢复 + +- HTTP 408、409、425、429、500、502、503、504 以及其他 5xx。 +- DNS、连接重置、临时网络错误、请求超时和响应读取中断。 +- 渠道熔断暂时开启或并发槽暂时不可用。 +- 查询返回 200 但响应暂时不是合法 JSON:允许有限次数连续重试,避免网关临时返回 HTML;连续 3 次后视为协议错误。 + +HTTP 429 的 `Retry-After` 大于 30 秒时优先遵守,但等待时间不得越过任务截止时间。 + +### 有条件恢复 + +- HTTP 404:连续 3 次查询都不存在后才结束,兼容供应商创建后异步同步任务记录的窗口。 +- 已有协议明确把某个业务错误定义为“尚不可查”时,统一纳入相同计数,不再维护供应商专属睡眠循环。 + +### 不可恢复 + +- HTTP 400、401、403、422 等明确的参数、鉴权或权限错误。 +- 插件清单无法构造请求、响应映射本身非法或本地校验失败。 +- 上游明确返回 `failed`、`cancelled`、`canceled`、`expired` 等终态。 +- 用户主动取消或宿主关闭导致的上下文取消。 + +## 下载阶段 + +结果状态成功后,媒体下载复用同一可恢复网络错误分类。下载最多连续尝试 3 次,每次至少等待 30 秒并遵守 `Retry-After`;仍失败时返回带供应商任务 ID 的明确错误,人工恢复仍可只查询原任务并再次下载,不创建新任务。 + +## 超时与运行时策略 + +- 全局视频任务默认超时从 30 分钟调整为 60 分钟。 +- 已保存的管理员运行时策略保持原值,升级不静默覆盖管理员配置;管理员可手动调整为 60 分钟。 +- 所有等待和 HTTP 请求都服从任务上下文截止时间,不额外延长租约之外的生命周期。 + +## 日志与计费 + +- 每次上游 HTTP 失败仍保留 API 调用审计记录。 +- 可恢复的轮询异常不得触发任务终态、退款或重新创建供应商任务。 +- 首次进入重试和恢复正常时写任务日志;连续相同错误不按每次轮询刷屏。 +- 最终成功沿用现有结算流程;明确失败或总超时沿用现有失败与退款流程。 + +## 兼容与迁移 + +- 不修改数据库结构。 +- 声明式插件清单无需升级,已安装插件自动获得统一策略。 +- 内置视频协议只迁移其查询循环,不改变创建和响应解析代码。 +- 前端仍查询宿主任务状态,无需改变前端轮询间隔。 + +## 测试策略 + +先写失败测试,再实现: + +- 统一间隔常量为 30 秒,首次查询前也等待该间隔。 +- 声明式协议经历 `502 -> processing -> succeeded` 后成功,且只创建一次上游任务。 +- 一个内置协议经历网络超时或 503 后继续并成功。 +- 401、400 和明确失败状态立即结束。 +- 404 前两次重试、第三次结束;正常响应会重置连续错误计数。 +- `Retry-After` 生效且不越过上下文截止时间。 +- 下载在临时 502 后重试成功,不重复创建任务。 +- 上下文取消与总超时能够及时退出。 +- 后端完整测试 `go test ./...` 通过。 + +## 风险与控制 + +- 统一 30 秒会降低原来高频协议的结果发现速度,但显著减少供应商压力和限流概率;这是本次明确接受的产品取舍。 +- 持续故障会让任务保持运行更久,并占用 worker。通过现有并发上限、渠道熔断和 60 分钟总超时控制;后台状态机另行设计。 +- 过宽重试可能掩盖配置错误,因此鉴权、参数、映射和明确终态不进入重试。