跳到正文

大型后台管理系统如何把业务操作做可靠(6):批量操作的预览、执行与恢复

大型后台管理系统如何把业务操作做可靠

  1. 把业务规则写进订单和退款模型
  2. 并发编辑、草稿合并与搜索乱序
  3. 让报表说清统计口径与数据进度
  4. 退款超时后的幂等与对账
  5. 可恢复的导入导出任务
  6. 批量操作的预览、执行与恢复(当前)
  7. 多租户授权、撤权与审计
  8. 旧页面、接口和审批模板如何一起演进
  9. 沿真实操作验收可靠性与性能
  10. 设计规范和组件库如何落到日常开发
  11. 脚手架、接口契约与前后端联调
  12. 构建产物、持续交付与灰度回退
  13. 低代码表单与审批流程的执行边界
  14. 功能投放、权限与灰度人群
  15. 桌面、移动端与宿主能力适配
  16. 多个前端应用如何集成与独立交付
  17. 复杂编辑器的状态、命令与协作

运营勾选了全部搜索结果。预览显示 10 条候选里有 8 条可下架。确认前又新增两条匹配商品,计划中的一条则已经被其他人修改。执行时最多只能触达先前确认的 8 条,能否处理每一条还要看当前状态。

先定义选中的范围

交互上至少要分清当前页、用户显式勾选的 ID 和所有匹配结果。后两种可以跨页,全选匹配时还可能排除若干条。预览接口接收选择表达式,用服务端确认过的租户与权限解析目标,将排除、不可见与不可操作分别处理。展示统计时避免用数量透露调用方不可见的记录。页面布局、确认框和失败结果可参考配套的 UX 文章。《后台管理系统常见 UX 问题总结》

保存执行计划,确认时只传计划 ID

下面的示例是预览阶段返回给运营的内容。服务端保存完整计划和 8 条明细,页面可以分页查看,确认请求只引用计划 ID 和本次确认的操作标识。

{
  "planId": "P19",
  "action": "unpublish_products",
  "matchedVisible": 10,
  "eligible": 8,
  "excluded": 2,
  "expiresAt": "2026-11-03T11:10:00+08:00",
  "previewSample": [{ "id": "SKU42", "expectedVersion": 7 }]
}

计划关联发起身份、租户、动作、目标及必要版本,确认时校验有效期和操作者资格。一次性计划可以用唯一约束保证只创建一项执行任务。大规模计划可分批持久化明细,或者引用确实能复现目标的不可变快照。仅保存筛选表达式和匹配数量,无法在数据变化后复现原集合。

十条候选中八条进入计划,其中一条执行前失效,最终处理七条

执行时复核资格和状态

以商品下架为例,可以逐项复核权限、商品归属、版本和当前上架状态,再做带条件的更新。版本变化的记录按产品规则跳过并返回可理解的原因。若同一计划不能容忍部分完成,就在同一事务边界内处理可原子提交的范围。跨系统或跨分片的大批操作通常要设计补偿、人工确认或明确的逐项语义。

情况 示例处理
新增匹配项 不进入这份计划
原目标已删除 记录目标已不可用
原目标版本变化 跳过并说明需要重新预览
操作者失去权限 依据撤权规则停止后续处理
执行端崩溃 接手后从已提交的逐项结果恢复

对于影响大的操作,可以先处理小批次并观察结果,再继续推进。计划支持暂停时,需要说明正在执行的工作单元是否会跑完。对已经生效的下架可以另建恢复计划,并检查下架后是否有新的正常修改。直接把整个商品恢复成旧快照,可能抹掉后来改过的价格和库存。

Atlassian 的 2022 年事故中,原意是清理旧应用,传入的却是整个站点的标识。删除接口接受两类对象,导致 775 个客户受影响,部分客户最长中断 14 天。资源类型应由明确的命令和服务端校验约束,恢复流程也需要实际演练。Atlassian 事故复盘

预览、确认、执行各自保存什么

假设候选是商品 A 到 J,其中 I 和 J 不符合下架条件。服务端保存 A 到 H 的版本和必要的影响信息,页面确认的是这一份清单。如果以后要解释为什么 I 没有执行,预览记录也应保留排除原因,但不要把 I 写进可执行目标。

确认时允许用户从已预览目标中再去掉几项,具体可以生成一份新计划,或者用受约束的子集确认。若操作者添加了新目标,必须再经过预览。服务端校验确认是否属于当前主体、租户和动作,还要保证预览过期后不会被旧请求重新使用。

confirmPlan(actor, planId, confirmationKey):
  transaction:
    plan = lockPlanWithinTenant(actor.tenant, planId)
    requireCanConfirm(actor, plan)
    if plan.confirmed:
      return matchingExistingJob(plan, confirmationKey)
    requireNotExpired(plan)
    requireWithinLimit(plan.targets)
    job = createJobForPlan(plan.id)
    markConfirmed(plan, job.id, confirmationKey)
    recordOutbox(job.id)
  return job

在这套示例策略中,确认以后计划不会扩张。执行过程中如果 D 版本变化,执行端给 D 写入跳过结果,A 到 H 中其余 7 条继续。运营看到的结算应同时显示「候选 10、排除 2、计划 8、成功 7、跳过 1」,计数都能下钻到具体明细。

恢复也要尊重别人后续的修改

如果七条下架中有三条需要恢复,另建恢复计划并展示哪三条仍可恢复。只恢复上架状态所需的字段,并核对商品当前状态和原操作之间的关系。例如某条商品下架后因违规被另一个流程锁定,恢复动作应拒绝或交给复核。价格在下架后被正常更新,则不应一并重置。

故障后的回退有三个层次。尚未执行的批次可以暂停,已经执行的本地状态可以走有条件的反向操作,已经发送的外部通知则需要业务认可的补救流程。把这三种结果分别记录,事故处置时才能知道还有哪些影响未消除。

用数据变化检验确认是否有效

创建计划以后新增两条匹配项,再修改计划中的一条。确认并执行,应只下架其余 7 条。重复点击确认仍查到同一任务。最后再演练恢复,并保留另一位运营在下架后补写的字段。通过这些例子可以同时检查目标范围、逐项结果和恢复边界。

总结

预览确定操作对象,确认记录操作意图,执行检查当前资格。三步各自保留数据,才能解释为什么确认了 8 条、实际完成了 7 条,以及剩下一条该怎么处理。