Publishing workflow · 2026-09-02

内容发布状态机与幂等,怎样真正阻止重复发布?

先定义任务身份,再讨论重试

在真实发布链路中,同一篇内容可能有官网母页、多个平台衍生稿和多次事实修订。若只用标题或正文摘要去重,改一个标点就可能生成新任务;反过来,两篇同名但证据不同的稿件又可能被误合并。任务身份应绑定租户、目标平台、内容资产和冻结版本。排期是可变的执行条件,不是业务身份:从上午改到下午,不得因此取得第二次提交资格。新版本也只获得重新审核的资格,不能自动获得外部发布授权。

内容发布任务从候选、冻结、审核、排期、执行到公开核验的状态迁移与幂等重放分流图
图可左右滑动查看。同一任务重放时回读已有状态;改排期不重置提交资格,新版本仍须独立审核与授权。
检查面应保留的证据常见误判
状态只允许按定义的边迁移不能靠按钮名称猜测结果
幂等键同一租户、平台与发布版本唯一标题相同不等于同一任务
租约执行者、到期时间与续租事件可回读进程存活不代表仍持有执行权
完成证据平台回执或合规公开地址填入、预览和保存草稿都不是发布

状态机负责解释“现在在哪”,幂等负责回答“是不是同一次”

两者不能互相替代。状态机约束候选、证据冻结、机器检查、独立批准、排期、执行、公开核验等阶段;幂等键则保证相同任务被重复领取、网络重试或进程恢复时,不会再次提交。每次迁移要记录前态、后态、原因、时间和执行者。若平台结果不可见,应进入未知或待人工复核,而不是为了让计数闭合写成失败或成功。

并发测试要覆盖两个执行器同时领取、租约刚好到期、完成回执写入前进程退出,以及平台已接收但本地超时。正确结果不一定都是“自动继续”:外部提交是否发生不明确时,安全动作是停止、保存页面与请求证据,再按平台规则核对。

失败重试为什么必须区分内部动作和外部动作

读取候选、计算哈希和生成预览通常可以安全重放;点击提交、确认发布或调用外部发布接口则可能产生不可逆副作用。执行器应在外部动作前写入尝试编号,在获得明确回执后再登记平台状态。若回执丢失,不能仅因本地没有完成事件就再次点击。

一个可复现实验是人为中断三个位置:领取后、提交前和提交后回读前。随后启动第二执行器,核对它是否分别继续内部准备、接管过期租约、或停在“外部结果未知”。这比只测试一条成功路径更能发现重复发布风险。

回执丢失时,先看故障切在哪一侧

下面是故障注入设计,不是平台实测统计。固定同一业务键,在四个位置结束执行器,再由第二执行器恢复。目的不是让每种故障都自动重试,而是确认什么时候必须停。

故障切点恢复时已知什么允许动作
只完成候选读取尚未进入外部动作区重做内部校验
提交意图已保存,无回执无法排除外部提交发生保留未知,核对平台
回执落盘,投影未更新外部动作已发生补投影,不再提交
公开证据已登记,调度再次触发同版本已有完成结果返回已有结果

验收时另改一次排期,外部提交计数不应增加。租约过期只解决“谁能继续”,不能证明“上一次没提交”。这与发布授权边界是两个检查面:授权有效不能消除未知副作用。

上线验收要同时看正向、负向和边界样本

  • 正常样本:一次领取、一次外部提交、一个明确回执和一个完成事件。
  • 负向样本:审核未通过、哈希变化或窗口未到时,执行器不得领取。
  • 并发样本:两个执行器只能有一个取得有效租约。
  • 边界样本:平台返回不明确时保留未知,不自动重复提交。
  • 租户样本:任何查询、幂等键和计数都不能跨租户串线。

事实是状态与事件可以证明发布流程发生了什么;建议是把重复出现的故障下沉为状态边和回归测试。未知项仍包括平台内部审核如何变化、公开页面能否被发现、索引或被模型选用,这些必须由后续独立证据回答。