网关超时返回 502,前端封装的请求库自动重试了一次,服务端其实两次都写入成功,后台同一个手机号出现两条报名记录,时间差 1.2 秒。第一次遇到会往复杂处想,其实漏掉的多是个小前提。

fetch('/api/signup', {
  method: 'POST',
  headers: {'Idempotency-Key': uuid}
});

重试逻辑对所有方法一视同仁,提交请求也被重试,服务端又没有幂等键,两次请求各自插入一条。前端只看到最后一次成功。这一点先确认清楚,后面就不用反复试。

碰到「自动重试重复写入」这类问题,我习惯先把当前配置原样备份一份,改坏了立刻换回来,不用现场推。把这次用到的命令存进笔记,比记住结论有用,换个环境还能照着走。

具体做法是,只对查询和明确幂等的接口自动重试,提交请求不重试;必须重试时带同一个幂等键,服务端按键去重;在数据库加唯一索引兜底,重复插入直接报冲突。

改完照着核一遍,模拟 502 重试后数据库只有一条记录,第二次请求返回第一次的结果。

作者 9823189