发布恢复:远端结果未知时禁止自动重放

自动关联目录:发布恢复:远端结果未知时禁止自动重放

核心判断:上传或远端保存超时后,“本地没收到成功”不等于“远端没生效”。无法查询或幂等确认结果时,自动重放比停止更危险。

一、业务冲突

内容发布包含分配身份、上传源文件、上传平台制品、保存元数据和更新封面。网络可能恰好在远端提交成功后断开。若客户端把超时一律视为失败并重试,可能重复分配身份、覆盖新版本或产生孤儿制品;若一律视为成功,又可能暴露缺失内容。

二、实际实现

管线为一次运行维护持久 Journal,记录请求摘要、Stage、已分配身份、对象上传状态和 resumeSafety。远端副作用开始前先把恢复状态设为阻塞,收到可验证结果后才恢复为安全;未知保存结果进入 reconciliation 状态,普通 Retry 会被拒绝。旧 Journal Schema 也不会被新代码直接重放云端写入。

三、值得保留

这正确地区分了“可重试错误”和“结果未知”。网络传输失败可以退避重试,业务拒绝直接等待人工修复,远端结果未知则先查询对账。测试覆盖了成功写入后丢响应、读回不完整和旧 Journal 恢复,说明恢复语义不是 UI 标签。

四、结构性缺陷

当前 Journal 同时承担状态快照、Effect 日志、进度和兼容信息,Stage 越多,嵌套字段与手工状态转换越复杂。一个可变 JSON 文件也难以证明每个远端 Effect 只执行一次,恢复代码需要理解多代历史形状。

五、目标设计

enum EffectState { Prepared, Sent, Confirmed, Rejected, Unknown };

struct RemoteEffect {
    EffectId id;              // 稳定幂等键
    IntentId intent;
    EffectKind kind;
    Hash requestHash;
    EffectState state;
    Optional<RemoteReceipt> receipt;
};

ResumeDecision Resume(RemoteEffect e) {
    if (e.state == Confirmed) return Skip;
    if (e.state == Unknown) return ReconcileOnly;
    return EndpointSupportsIdempotency(e.kind) ? Replay : Stop;
}

运行快照可由追加式 Effect Ledger 投影得到;升级只需新增投影器,而不是改写旧记录。远端接口若不支持幂等键,就必须提供按业务身份查询结果的对账路径。

六、取舍与验证

停在“待确认”会降低自动成功率,但它守住的是内容唯一性。验证应在每个远端调用的发送前、发送后、响应前和本地落盘前注入崩溃,证明恢复只会继续安全步骤,绝不盲目重放未知副作用。