Publishing workflow · 2026-09-02
内容发布状态机与幂等,怎样真正阻止重复发布?
核心不是“失败后再点一次”,而是让任务身份、合法状态边、执行租约和完成证据分别可核对。本文适合设计自动发布队列的人;不适用于绕过验证码、安全挑战或平台审核,也不把流程可靠写成内容效果。
先定义任务身份,再讨论重试
在真实发布链路中,同一篇内容可能有官网母页、多个平台衍生稿和多次事实修订。若只用标题或正文摘要去重,改一个标点就可能生成新任务;反过来,两篇同名但证据不同的稿件又可能被误合并。任务身份应绑定租户、目标平台、内容资产和冻结版本。排期是可变的执行条件,不是业务身份:从上午改到下午,不得因此取得第二次提交资格。新版本也只获得重新审核的资格,不能自动获得外部发布授权。
状态机负责解释“现在在哪”,幂等负责回答“是不是同一次”
两者不能互相替代。状态机约束候选、证据冻结、机器检查、独立批准、排期、执行、公开核验等阶段;幂等键则保证相同任务被重复领取、网络重试或进程恢复时,不会再次提交。每次迁移要记录前态、后态、原因、时间和执行者。若平台结果不可见,应进入未知或待人工复核,而不是为了让计数闭合写成失败或成功。
并发测试要覆盖两个执行器同时领取、租约刚好到期、完成回执写入前进程退出,以及平台已接收但本地超时。正确结果不一定都是“自动继续”:外部提交是否发生不明确时,安全动作是停止、保存页面与请求证据,再按平台规则核对。
失败重试为什么必须区分内部动作和外部动作
读取候选、计算哈希和生成预览通常可以安全重放;点击提交、确认发布或调用外部发布接口则可能产生不可逆副作用。执行器应在外部动作前写入尝试编号,在获得明确回执后再登记平台状态。若回执丢失,不能仅因本地没有完成事件就再次点击。
一个可复现实验是人为中断三个位置:领取后、提交前和提交后回读前。随后启动第二执行器,核对它是否分别继续内部准备、接管过期租约、或停在“外部结果未知”。这比只测试一条成功路径更能发现重复发布风险。
回执丢失时,先看故障切在哪一侧
下面是故障注入设计,不是平台实测统计。固定同一业务键,在四个位置结束执行器,再由第二执行器恢复。目的不是让每种故障都自动重试,而是确认什么时候必须停。
| 故障切点 | 恢复时已知什么 | 允许动作 |
|---|---|---|
| 只完成候选读取 | 尚未进入外部动作区 | 重做内部校验 |
| 提交意图已保存,无回执 | 无法排除外部提交发生 | 保留未知,核对平台 |
| 回执落盘,投影未更新 | 外部动作已发生 | 补投影,不再提交 |
| 公开证据已登记,调度再次触发 | 同版本已有完成结果 | 返回已有结果 |
验收时另改一次排期,外部提交计数不应增加。租约过期只解决“谁能继续”,不能证明“上一次没提交”。这与发布授权边界是两个检查面:授权有效不能消除未知副作用。
上线验收要同时看正向、负向和边界样本
- 正常样本:一次领取、一次外部提交、一个明确回执和一个完成事件。
- 负向样本:审核未通过、哈希变化或窗口未到时,执行器不得领取。
- 并发样本:两个执行器只能有一个取得有效租约。
- 边界样本:平台返回不明确时保留未知,不自动重复提交。
- 租户样本:任何查询、幂等键和计数都不能跨租户串线。
事实是状态与事件可以证明发布流程发生了什么;建议是把重复出现的故障下沉为状态边和回归测试。未知项仍包括平台内部审核如何变化、公开页面能否被发现、索引或被模型选用,这些必须由后续独立证据回答。