Skip to content

远程副作用、outbox 与未知状态 ​

本地数据库事务和远程邮件、支付或发布服务无法组成同一个原子提交。应用通常在本地事务中保存 outbox,再由 worker 使用业务幂等键发送;超时后先查询远程状态,再决定重试、等待或人工核对。没有查询和幂等能力的供应商只能返回 unknown,不能承诺 exactly-once。

第一个可运行实验:明确未知状态 ​

保存为 remote.py,用 Python 3.12 运行。

python
def decide_after_timeout(lookup_result):
    if lookup_result == 'succeeded':
        return 'reuse_result'
    if lookup_result == 'not_found':
        return 'retry_with_same_key'
    if lookup_result == 'pending':
        return 'wait'
    return 'manual_review'

assert decide_after_timeout('succeeded') == 'reuse_result'
assert decide_after_timeout('not_found') == 'retry_with_same_key'
assert decide_after_timeout('pending') == 'wait'
assert decide_after_timeout('unavailable') == 'manual_review'
print('remote outcome policy passed')

outbox 记录租户、业务动作、payload 摘要、幂等键、尝试次数和远程状态。worker 重启后复用同一业务键;不能因为模型生成了新的 call ID 就产生新的付款或发信意图。补偿动作也有副作用,必须单独授权和审计。

变体实验 ​

让远程查询本身超时,要求进入人工核对而不是盲目重发。再让供应商返回成功但本地 outbox 未更新,恢复时应查询并补写结果。

练习 ​

  1. 设计 outbox 的状态迁移:pending、sent、succeeded、failed、unknown。
  2. 为查询不到结果和查询服务不可用区分重试策略。
  3. 说明为什么取消请求不能证明远程副作用没有发生。

用心记录每一步成长