AIGC 平台做完页面之后:交付版本、视频访问与可回滚发布

一个创作平台最难交付的部分,往往不在首页。

创作者上传了新版本,客户却还在审核旧文件;付款后课程能播放,链接转发出去也能播放;应用回滚成功,数据库字段却已经无法兼容。功能逐项可用,并不自动等于整套业务可以可靠运行。

在 AIGC 制作、创作者协作和在线教学这类系统中,我会把交付理解为四件事:业务状态能解释,文件版本能追溯,权限在服务端成立,发布失败能恢复。

审核的是哪个版本,比“是否通过”更重要

交付单如果只有 approved=true,很难回答客户到底认可了哪个文件。文件被覆盖之后,审核意见就失去了明确对象。

更稳妥的结构是:订单、交付版本、交付文件、审核记录分别保存。交付版本不可变,新上传生成新版本;审核记录关联明确的版本 ID,保留审核人、时间、意见与文件校验信息。

真正需要防住的竞争,是客户打开版本 3 的审核页面后,创作者提交了版本 4,客户随后按下“通过”。审核请求必须携带预期版本:

1
2
3
4
5
6
7
8
UPDATE delivery_order
SET status = 'ACCEPTED', accepted_version_id = :expected_version_id,
revision = revision + 1
WHERE tenant_id = :tenant_id
AND id = :order_id
AND status = 'REVIEWING'
AND current_version_id = :expected_version_id
AND revision = :expected_revision;

服务端先验证当前用户的审核权限,再执行条件更新。影响行数为 0 时提示刷新核对,不能自动接受新的版本。更新、审核记录和结算待办事件放在同一个本地事务里,避免订单通过了却没有可追溯的审核依据。

“验收完成”也不应该直接等于“资金已到账”。延迟结算、争议处理、退款和提现是独立状态,不能挤在一个订单状态字段里。

延迟任务需要活过一次重启

自动验收和延迟结算如果只依赖进程内的定时器,容器更新后就会丢失。数据库里保存 due_at、任务身份、状态和重试信息,调度器只负责领取到期工作。

多个实例竞争同一任务时,需要原子领取与租约;任务执行前重新检查订单状态。用户在到期前发起争议,旧任务即使已经进入队列,也不能绕过争议状态继续结算。

完成任务的业务事务必须具备幂等约束,进程在事务提交后、更新调度状态前退出,恢复时才能安全重试。这与Outbox 消息处理属于同一类问题:记录业务事实,再让可重试的执行器推进它。

视频拖动播放,暴露的是整条代理链

课程视频能从头播放,却无法拖动,并不一定是播放器的问题。浏览器可能发送 Range 请求,媒体服务和中间代理都需要正确处理分段响应。

先观察实际网络交换:有效范围通常返回 206 Partial Content 和匹配的 Content-Range;不可满足的范围返回 416。没有 Range 的普通请求可以返回完整内容。处理逻辑应交给成熟的媒体服务或对象存储,避免自行实现一个只覆盖正常范围的字符串解析器。HTTP Range 请求

排查时沿浏览器、业务网关、媒体代理、存储逐层核对请求头与响应头,确认是否有人把 206 改成了 200、去掉范围头,或把整个大文件加载进应用内存。

分段播放也必须经过授权。课程购买状态在签发短期媒体地址或令牌前由服务端判断;直接对象地址不能长期公开。短期签名 URL 在过期前可能被转发,它限制的是访问窗口,并不提供绝对防复制能力。

CDN 缓存尤其需要谨慎:仅在回源时检查 Cookie,无法保证后续缓存命中也经过相同授权。要么在边缘验证权限,要么使用明确隔离、限时签名的资源策略,避免把个人授权响应缓存成公共内容。

上传成功,应该有可追溯的完成点

应用接收文件后先写临时位置,检查大小、文件类型与业务归属,再发布为不可变文件。客户端传来的文件名不能直接拼接成服务器路径;展示名与存储键应分离。

数据库与文件存储不是一个事务。可以用 UPLOADING、READY 等状态描述上传过程,只有文件完成且校验通过才允许业务引用。失败的临时文件由清理任务处理;清理前确认它不再被有效上传或交付版本引用,避免误删正在完成的文件。

容器可写层也不应该成为唯一存储位置。上传文件、数据库和配置分别确定持久化位置与备份策略;应用镜像只承载可重建的程序。备份是否有效,需要通过恢复后的实际读取验证。

蓝绿发布的难点,是旧程序还能否读新数据

镜像打上不可变版本号,部署绿环境,验证后切换入口,保留蓝环境用于回退——这个流程并不复杂。难点在于数据库变更和后台任务。

数据库优先采用扩展后收缩:先增加兼容字段,部署能兼容旧数据的程序,完成回填与观察,最后才删除旧字段。若新版本已经写入旧程序无法理解的数据,单纯切换镜像并不能完成回滚。

两个版本同时运行期间,自动验收、结算等后台任务也可能同时执行。任务租约与业务幂等要跨版本成立,或者明确只有一个版本承担调度;否则蓝绿发布会把原本偶发的重复处理变成固定行为。

Compose 的启动顺序不等于服务可用。service_healthy 可以让依赖健康检查参与启动顺序,但应用仍需处理运行期间的依赖中断,并提供自己的就绪检查。Docker Compose 启停顺序

发布验证要覆盖一次真正的业务往返

健康接口返回 200,只能说明对应处理器还活着。发布后的验证应覆盖登录与权限、列表与详情、受保护媒体、文件持久化,以及一个无资金副作用的任务流转。

对结算、支付和批量设备操作,不直接用真实资金或设备做随意探测。使用隔离账号、测试数据和可控环境验证状态机,再对生产环境进行只读核对。

一套发布方案能否放心使用,取决于它是否写清楚:何时停止切流、哪些数据仍兼容旧版、如何处理未完成任务、恢复后怎样确认业务连续。把这些问题提前回答,才算把平台从“功能完成”推进到“能够维护”。