重复执行前,先说明部分成功批次的逐项结果
本文目录
一个批次部分成功后,应先报告每一项的结果,以及能说明其实际效果的证据,再提供下一步操作。成功、跳过、失败和未知的项目,需要不同的后续处理。重复执行原始选中项,可能覆盖后来的工作,也可能重复产生已经发生的效果。
批次层面的响应无法回答所有这些问题。Microsoft Graph 的 JSON 批处理文档提供了一个具体协议示例:外层响应为 200,并不表示里面每个请求都成功。这项特定服务的区分说明了为何需要检查逐项结果,但不能替所有应用定义恢复规则。
下面是一个虚构的五条笔记列表操作,不是 Graph 请求,也不是记录下来的响应。所有回执和结果都是为教学编写的数据。没有任何笔记被修改,也没有调用 API。
标明批次及预期的逐项效果
请求的操作是把五条选中笔记的标签设为 Ready。虚构批次为 B7。每一项也有自己的请求标识,以便把逐项结果对应到预期的那次尝试,而不是对应到恰好位于某个显示位置的行。
假设虚构的外层响应为 200:应用收到了外层封装。应把这一传输事实与逐项记录分开:
| 项目 / 请求 | 尝试前最后已知的标签 | 编写的逐项证据 | 已确认的效果 | 结果 |
|---|---|---|---|---|
| N11 / O11 | Draft | O11 的已应用回执 | 标签改为 Ready | 成功 |
| N12 / O12 | Draft | O12 的已应用回执 | 标签改为 Ready | 成功 |
| N13 / O13 | Ready | 跳过回执:已是 Ready | 没有新写入 | 跳过 |
| N14 / O14 | Draft | 修改前即被明确终止并拒绝:缺少必填分类 | 无变化 | 失败 |
| N15 / O15 | Draft | 未收到逐项结果 | 未知 | 未知 |
这里的请求标识和回执术语属于这份虚构约定。它们不意味着某个特定 SDK 提供了操作状态查询端点,或采用这些字段。
N13 有明确的跳过原因,不能把它算作第三次新成功的更新。N14 的失败结果包含证据,说明这次尝试没有修改项目。不能把这种“无效果”的结论泛化到其他服务的所有错误。N15 最后已知的 Draft 标签,也不是它当前标签的确认结果。
让汇总数量对得上,同时保留不确定性
这五项应显示为:
2 项成功 · 1 项跳过 · 1 项失败 · 1 项未知
四个计数之和为五。有两项已确认产生效果,两项已确认没有写入,还有一项效果未明。不要为了让结果看起来已经收尾,就把未知项归入失败计数。
界面应保留查看逐项说明的入口。“已完成,但有错误”这样的汇总,无法告诉用户该修正输入、保留已成功的项目,还是调查缺失的回执。
把后续工作分成不同集合
初始恢复计划是:
| 集合 | 成员 | 当前允许做什么 |
|---|---|---|
| 保持不动 | N11, N12, N13 | 不自动重复执行 |
| 审查待修正的输入 | N14 | 检查并准备修正;不立即重复执行 |
| 核实原始尝试的结果 | N15 | 再次修改前,先确认 O15 的结果 |
| 立即重复执行 | 无 | 不立即重复 B7,也不凭猜测重复执行某个子集 |
N14 可以作为待修正项,是因为虚构回执说明 O14 已终止且没有修改。它仍需重新检查当前的分类、权限、项目状态和预期的新输入。过去的失败,既不等于现在有权修改,也不能证明同样的被拒输入以后会成功。
对于 N15,只检查标签现在是否为 Ready,可能无法确定 O15 究竟发生了什么。另一个操作也可能产生相同标签。应使用所选应用实际提供的、权威的项目或尝试证据。如果无法建立对应关系,就应保留未知结果,不能凭猜测再发起一次尝试。
核实未知项,但不改写历史
以下是初始逐项记录之后的三种可选后续情况,不是同一次执行中的三个步骤:
| 后来获得的 O15 证据 | 更新后计数:成功 / 跳过 / 失败 / 未知 | 下一步解释 |
|---|---|---|
| 确认原始那次尝试已应用 | 3 / 1 / 1 / 0 | N15 成功;不再应用一次 |
| 确认原始那次尝试已终止且未应用 | 2 / 1 / 2 / 0 | N15 成为另一个待审查项,再判断是否可发起新尝试 |
| 仍无明确的原始尝试状态 | 2 / 1 / 1 / 1 | N15 保持未知;不自动重复执行 |
应把最初缺失回执的记录与后续证据一起保留。后来的更新应说明分类为何变化,不能让人以为应用从一开始就知道结果。
这张表没有指定通用的核实 API。它明确的是,在再次操作之前,读者需要什么证据。实现者必须确定实际服务能否提供这些证据,并在无法提供时定义保守的处理路径。
根据当前输入和权限重新检查修正方案
假设有人补齐了 N14 缺少的分类。此时拟议的恢复操作包含已改变的输入。它是经过审查的修正尝试,不是对已被拒绝的 O14 盲目重复。
| 审查恢复方案时的情况 | 修正请求的候选项 | 选定操作 |
|---|---|---|
| 分类已补齐;当前权限允许;标签和意图仍适用;用户确认修正后的预览 | N14 | 用修正后的输入准备一次新尝试 |
| 当前权限已不允许这项修改 | 无 | 阻止修正,并说明当前限制 |
| 标签已变为 Approved,或拟议的恢复输入再次发生变化 | 暂无 | 覆盖任何内容之前,重新审查当前意图和输入 |
最后一行防止旧批次指令把后续进展改回去。即使再次设置相同标签看起来没有影响,当前项目也可能已不再对应同一个决定。恢复界面应显示当前目标和拟议修改,不能只展示旧错误。
如果最终执行了修正尝试,应根据该次经过审查的输入和标识单独记录结果,并关联到它所处理的失败请求 O14。不要把原来被拒绝的尝试改写为成功记录。
具体说明重复执行的风险
重复 B7 会再次包含已确认产生效果的 N11 和 N12,也会包含被有意跳过的 N13,以及效果仍未明确的 N15。如果不修改请求,还会重新使用 N14 的无效输入。
问题不只在于,在这个小例子里,把 Ready 写两次是否碰巧得到同一个可见标签。实际实现可能涉及后来的编辑,或其他附加效果。本文既没有声称这些效果存在,也不假设重复写入没有影响。它要求实现者先明确操作的实际语义,再提供重复执行功能。
部分恢复也不等于回滚那两项成功。撤销是另一项决定,需要单独考虑适用状态和历史。本例选择保留已确认的结果,只处理有依据的后续操作。
复制这份部分成功处理需求
为虚构批次 B7 规划恢复界面,该批次把笔记标签设为 Ready。
只使用本地案例。不得发出真实请求或自动修改项目。
初始逐项记录:
N11/O11:成功;有已应用回执;标签改为 Ready。
N12/O12:成功;有已应用回执;标签改为 Ready。
N13/O13:跳过;已是 Ready;有明确的“无新写入”回执。
N14/O14:失败;缺少分类;修改前即被终止并拒绝。
N15/O15:未知;缺少逐项回执;最后已知 Draft 不构成当前状态的证据。
编写的外层响应为 200,不能代替这些逐项结果。
初始汇总:
2 项成功、1 项跳过、1 项失败、1 项未知,共 5 项。
保持 N11/N12/N13 不动。审查 N14 的修正方案。核实 O15 的结果。
立即重复执行集合为空。不要默认提供“全部重复执行”。
未知项情况:
如果确认确切的 O15 已应用:计数为 3/1/1/0,不重复 N15。
如果确认确切的 O15 已终止且未应用:计数为 2/1/2/0,
审查 N15 是否可发起新尝试;不要自动发出请求。
如果仍未解决:保留 2/1/1/1。标明未知,并报告证据缺口。
保留原始缺失回执的历史,以及后来的任何核实结果。
修正情况:
只有补齐分类、当前权限允许、当前标签/意图仍适用,
并且用户确认新输入后,N14 才能成为修正尝试的候选项。
输入改变,应另建一次经过审查的新尝试。
权限已撤销:没有候选项。标签现为 Approved,或输入再次改变:
回到审查,不应用过时的 Ready 指令。
检查当前的批次封装、逐项结果对应关系、权威的效果/状态证据,
以及修正输入/权限检查。注明文件。
区分“有证据确认无效果的失败”和缺少这种证据的错误。
返回逐项记录、精确计数、审查/核实/操作子集,以及范围明确的实现计划。
把所附案例作为预期;另行记录实际运行过的检查。
指出实际服务无法提供哪些证据。不要声称批次具有原子性,
也不要声称效果恰好发生一次。
本步骤不得调用真实 API、配置 SDK、访问账号、安装依赖、修改生产环境、
自动重试、回滚、发布内容或部署。
一个离线 Python 3.12.14 模型检查了编写的逐项记录计数、三种可选的核实结果汇总,以及拟议的工作集合。它没有执行任何标签修改、查询操作状态,也没有证实 Graph 或其他服务的行为。针对实际应用的证据,仍然是决定真实恢复操作的依据。