为后台作业定义受理之后的完整契约
本文目录
后台作业需要的不只是加载动画和最后一句“完成”。在让编程 Agent 实现它之前,先定义服务受理了什么、正在进行哪项工作、用户可以获取哪些输出,以及观察中断后应如何处理。
Microsoft 的异步请求-应答模式区分受理响应、状态资源和最终结果。在该模式下,即使作业仍在运行,一次成功的状态查询也可以返回 HTTP 200。其建议的状态字段包括时间戳、可选进度指示和错误。这些可以作为起点,但应用仍需要自己的状态与结果契约。
为一个作业定义三个具体阶段
虚构应用 Atlas Bundle 根据内置预设生成一组可下载的文本卡片。下文所有 ID、路径、历史与时间都是原创教学数据。本例没有实际运行服务、队列、渲染器或下载接口。
完整输入如下:
{
"job_id": "j-41",
"preset": "coast",
"pages": ["cover", "summary"],
"format": "text-bundle-v1"
}
预设的初始计划包含 cover-title、cover-key、summary-counts 和 summary-notes。展开计划时又发现两个必需的配套项:cover-legend 和 summary-source。这六个名称也分别对应最终的 .txt 文件名。本例不依赖客户文档或真实渲染软件包。
| 阶段 | 工作单元 | 完成条件 |
|---|---|---|
| 校验(Validate) | 一项检查:结构、预设、页面列表或格式 | 四项检查全部通过 |
| 构建(Build) | 一张具名文本卡片 | 修订计划中的六张卡片全部存在于私有暂存区 |
| 打包(Package) | 一项动作:先写入 manifest.json,再写入 bundle.zip |
两项动作均完成;归档索引包含六张卡片与清单 |
拟议清单列出作业 ID、格式和六个文件名。这里的归档索引是一项要求,不是本文已经生成的归档。打包后,服务必须发布暂存的文件包,并建立所属用户可访问的结果获取路径,之后才能把作业标记为 succeeded。
配套数据 B62-14-case.json 包含输入、具名工作单元、归档索引,以及下文使用的全部四份历史。
把状态与结果交付分开定义
采用以下服务端状态转换。允许多次观察到同一个未变化的状态。
| 当前状态 | 允许的下一状态 | 含义 |
|---|---|---|
accepted |
running、cancel_requested |
作业记录已存在;执行不一定已经开始 |
running |
running、cancel_requested、succeeded、failed |
工作正在进行;一个阶段结束不代表整个作业结束 |
cancel_requested |
canceled、succeeded、failed |
取消仍待处理;服务必须裁决这场竞争 |
succeeded |
不再进入新的执行状态 | 结果发布已完成 |
failed |
不再进入新的执行状态 | 本次执行已结束,并记录了错误 |
canceled |
不再进入新的执行状态 | 服务确认已在结果发布前停止 |
交付使用另一组取值:none、partial_private、staged_private、available、blocked 或 expired。它们是拟议的应用字段,不是 HTTP 状态码。
按照这份契约,部分卡片始终不可下载。本地暂存文件已经完成也不够,因为发布仍可能失败。成功作业在发布时应有所属用户可访问的结果引用;某个客户端之后的获取仍可能失败。应把该次获取的观察结果与作业状态分开。
走完成功历史,不编造预计完成时间
时间均为虚构数据中的已过秒数。进度始终标明所属阶段与计划修订号。
| 时间 | 作业状态 / 阶段 | 阶段工作量 | 交付状态 | 用户可以得出什么结论 |
|---|---|---|---|---|
| 0 | accepted / validate | 0 / 4 | none | 已接收,尚未开始 |
| 1 | running / validate | 0 / 4 | none | 已开始校验 |
| 3 | running / validate | 4 / 4 | none | 校验完成;作业仍在运行 |
| 4 | running / build,修订 1 | 0 / 4 | none | 已选定初始构建计划 |
| 6 | running / build,修订 1 | 2 / 4 | partial_private | 两张卡片已存在于私有区域 |
| 7 | running / build,修订 2 | 2 / 6 | partial_private | 又发现两张必需卡片 |
| 10 | running / build,修订 2 | 6 / 6 | partial_private | 卡片创建完成 |
| 11 | running / package | 0 / 2 | partial_private | 已开始打包 |
| 13 | running / package | 2 / 2 | staged_private | 文件包已暂存;仍待发布 |
| 14 | succeeded / package | 2 / 2 | available | 结果已发布到 /jobs/j-41/result |
| 74 | succeeded / package | 2 / 2 | expired | 保留期已结束;该作业此前仍然是成功的 |
分母变化时,构建进度会从 50% 变成约 33%。保留已完成单元,并增加计划修订号;可以解释为“6 张卡片中已完成 2 张;计划已扩展”。不要悄悄重置已完成工作,也不要继续显示旧百分比。
这些工作单元的耗时不同。四项校验、六张卡片和两项打包动作,并不等于十二个耗时相同的时间片。因此,这个设计只显示各阶段计数,不给出整体百分比或剩余时间估计。即使打包动作已经达到 2 of 2,在发布之前也不代表“可以下载”。
本练习规定,结果在发布后保留 60 秒,因此 j-41 的边界是 t=74。真实产品应认真选择保留期。过期后应报告“已完成;结果已过期”,而不是悄悄重新运行作业。
说清失败与观察中断的含义
| 案例 | 记录的证据 | 本契约中的决定 |
|---|---|---|
j-42 构建失败 |
校验完成;构建达到 2 / 6,随后在 t=8 出现 TILE_BUILD_FAILED |
最终状态为 failed;部分产物被阻止交付;没有结果链接 |
j-43 确认取消 |
0 时受理;1 时校验完成 1 / 4;2 时请求取消;3 时停止 | 最终状态为 canceled;没有结果链接 |
j-44 取消竞争 |
校验和构建已完成;13 时打包达到 2 / 2;13.2 时请求取消;14 时发布获胜 | 最终状态为 succeeded;显示“取消生效前已完成” |
| 状态查询超时 | 客户端最后在 t=7 看见 j-41;t=20 时无法读取状态 |
客户端显示状态不可用,最后已知为构建 2 / 6;它仍不知道服务端结果 |
| 成功后获取结果失败 | 客户端已获得 succeeded 状态,但无法获取结果 | 保留 succeeded;显示获取问题,不编造下载成功 |
不知道最新情况属于客户端观察条件,不是服务端执行状态。本数据规定,最后更新距今超过十秒时标为陈旧,不会自动转成 failed。到 t=22,一次新的成功状态查询可以揭示:j-41 已于 14 时完成。状态失联期间没有重新启动或取消它。
同样,停止等待只停止这个客户端的观察。请求取消是请服务停止工作。在服务记录最终取消之前,两者都不能证明已经取消。最终状态裁决必须与发布过程串行协调,避免界面对同一次执行同时报告已取消和已成功发布。
恢复应从已记录的状态开始。对于已知的最终失败,检查错误,并在适当时提议一个经明确请求的新作业。本例没有提供可恢复检查点契约。对于丢失的状态响应,应先恢复对现有作业状态的查询;创建另一个作业会产生新的副作用。
给 Agent 完整生命周期,不只给按钮文案
设计虚构 Atlas Bundle 的作业协议和客户端展示。
依据 B62-14-case.json 以及本指南的状态与表格。
输入为预设 coast,页面 cover 和 summary,格式 text-bundle-v1。
校验四项具名检查。先构建计划中的四张卡片;展开计划时
增加 cover-legend 和 summary-source,在计划修订 2 下保留已完成工作。
打包 manifest.json 和 bundle.zip。只有所有必需输出完成,
且已建立所属用户的结果获取路径后,才能发布。
把服务端执行状态、阶段/计数/计划修订号、交付状态,
以及客户端观察/获取状态分开。状态 HTTP 200 表示一次读取结果,
不是作业成功信号。始终不开放私有部分产物或暂存文件。
使用状态转换表,包括 cancel_requested 最终变为 canceled、
succeeded 或 failed。为发布与取消定义一个按串行顺序裁决的获胜结果。
停止等待是本地动作,不会取消服务端工作。
结果之后过期时,不改变最终执行状态。
走查 j-41 的成功与分母扩展、j-42 的失败、j-43 的取消、
j-44 中发布赢得竞争,以及 t=7 到 t=22 的状态观察缺口。
为每个案例给出确切的可见标签,以及是否可提供结果链接。
使用阶段工作单元,不编造整体百分比或预计完成时间。
先返回完整的状态/输出/错误矩阵,以及拟议的状态/结果表示。
指出实现必须保障的持久化、发布和取消边界。
缺失的检查点、访问和保留期实现决定应明确保留;数据中的
60 秒保留期仅供说明,不是生产要求。
此任务只使用本地教学模型。不要创建 worker/队列,
调用云 API、部署接口,或因状态超时就创建新作业。
分开记录模型检查、真实实现证据与尚未确定的事项。
这个生命周期延续了创建回执之后的工作。它不替代另一个决定:重试创建是否仍指向同一个预期作业。把两份契约分开,评审者就能提出两个有明确答案的问题:创建了哪个作业,以及之后这个作业发生了什么?