一次媒体生成任务的生命周期
长时间运行的媒体生成不是一次 API 调用,而是需要持久状态、恢复、结算与交付的分布式作业。
接入第一个媒体生成模型时,系统通常看起来非常简单:提交参数,等待返回,拿到图片或视频。
当模型变多、生成时间变长、供应商开始返回任务 ID,而产品又需要处理重试、扣费、退款和文件交付时,这个抽象很快就会失效。表面上仍然是一次 API 调用,真实发生的却是一项跨越多个系统、持续数分钟的分布式作业。
我们在拆分媒体生成服务时,最初关注的是语言、部署和供应商适配。真正困难的部分后来才显现出来:谁拥有任务状态,什么时候算成功,以及在网络已经失去确定性之后,系统如何仍然作出正确决定。
请求结束时,生成才刚刚开始
同步接口隐含了一个简单假设:请求返回时,工作已经完成。
媒体生成恰好相反。调用方提交任务后,上游可能只确认“已接受”。真正的计算随后才发生,期间可能排队、运行、失败、重试,最终再产生一个可下载的结果。
因此,“创建成功”和“生成成功”必须是两个不同的事实。前者只说明系统已经接住工作,后者才说明用户得到了结果。
如果把它们压进同一次请求,超时就会变得非常危险。调用方看到的是失败,但生成服务可能已经成功创建任务。此时重新提交会制造重复作业,直接退款可能造成已经生成却没有结算,继续扣费又可能让用户为一个无法看见的结果付费。
网络超时不是失败结论。它只代表调用方不知道发生了什么。
一项任务只能有一个状态权威
一条媒体生成链路里,常常同时存在产品后端、生成服务和外部计算平台。它们都会保存一部分状态,也都可能对“任务在哪里”给出自己的答案。
如果每一层都独立推断最终状态,系统很快就会分裂:一层认为任务创建失败,另一层仍在生成;一层已经退款,另一层随后返回成功;用户关闭页面后,负责更新结果的那一层也停止工作。
可靠的设计需要一个明确的 job identity,以及一个对生命周期拥有最终解释权的状态记录。任务可以经历 accepted、running、succeeded、failed 等阶段,但状态转换必须可追踪、可重复读取,并且不能依赖某个浏览器标签页仍然存在。
其他系统可以观察任务,却不应该各自发明任务事实。
轮询只是观察,不是执行
异步生成通常通过轮询获取结果。问题不在轮询本身,而在我们很容易把轮询误认为任务的驱动力。
如果只有前端持续查询时,后端才检查状态、保存结果或完成结算,那么用户关闭页面就等于终止了系统责任。生成仍可能在外部完成,但产品永远不知道。
轮询应该只回答“现在发生到哪里了”。任务推进、终态确认、Artifact 保存和结算不能由观察者是否在线决定。
同样,服务内部也不应该无条件维护另一套高频轮询,而调用方又重复做相同的事。需要先明确谁负责 reconciliation,其他查询只读取同一份状态。否则更多轮询只会带来更多竞态和成本。
幂等处理的是不确定性
人们经常把幂等理解为防止用户重复点击。对于长任务,它更重要的作用是处理系统无法确认上一次调用结果的时刻。
请求可能在上游创建任务之后断开,回调可能重复到达,状态更新也可能被两个实例同时执行。任何一步如果被再次运行,都必须先判断对应事实是否已经存在。
这意味着一项生成不能只依赖每次调用临时产生的 request ID。系统需要稳定的业务 job identity,让创建、查询、保存 Artifact 和结算都能够指向同一项工作。
重试不是再做一次。重试是再次尝试把系统带到同一个目标状态。
文件是终态的一部分
许多生成平台返回的结果 URL 并不稳定。它可能有时效,也可能在重复查询时发生变化。如果产品只把最近一次 URL 原样交给用户,就仍然没有真正拥有交付结果。
生成成功之后,系统需要把外部结果转化为自己的 Artifact:保存稳定地址、内容类型、来源关系和所属任务,并确认它已经可被用户持续访问。
因此,成功不应该定义为“上游返回了一个 URL”,而应该定义为“产品已经获得并保存了可交付的结果”。
这个边界也决定了结算时机。计算结束、文件可用和用户完成交付是相关但不同的事实,系统必须知道自己依据哪一个事实收费或退款。
抽象应该统一语义,而不是抹平差异
多供应商服务很容易追求一个完全统一的接口:所有模型都接受相同参数,返回相同结构。
但不同模型对尺寸、时长、参考素材和生成模式的支持并不相同。强行抹平差异,通常只是把限制藏进实现,在运行时才以奇怪的失败暴露出来。
更好的抽象是统一 job lifecycle、错误语义和 Artifact 结果,同时显式表达能力差异。调用方可以根据产品策略选择模型与供应商,生成服务则负责把每一种实现映射到同一套任务事实。
统一的是系统如何理解工作,而不是假装所有能力都一样。
成功率首先是一个定义问题
当系统开始统计成功率,另一个问题随之出现:什么算服务失败?
输入素材不合法、内容被拒绝、模型暂时过载、网络异常和内部状态丢失都会让用户看不到结果,但它们对应完全不同的工程行动。如果全部归进一个 failure 数字,指标只会制造焦虑,无法指导修复。
可观测性必须保留失败发生在哪一层、是否可重试、责任属于输入还是服务,以及任务最终是否通过其他路径恢复。真正有用的成功率不是更好看的数字,而是能够对应明确 owner 和下一步行动的分类。
同样,成本不能只在供应商账单里事后查看。一次 job 从创建到交付,需要知道消耗发生在哪里、用户结算是否完成,以及失败路径有没有留下不一致。
媒体生成是一套 Job System
把媒体生成从主系统拆出去,最后带来的并不是一个更快的 API,而是一条更清晰的责任边界。
模型适配负责把任务交给计算平台;Job System 负责状态、幂等和恢复;Artifact 层负责拥有结果;产品系统负责策略与用户关系;可观测性负责证明这些部分是否一致。
语言和部署方式都只是实现选择。真正重要的判断是:当工作无法在一次请求内完成,就不应该继续假装它是一次请求。
如果生成需要几分钟,它不是 response。
它是一项 job。


讨论
评论区
关于文章本身,也欢迎留下不同意见或补充。