Stripe 后台连续重发同一事件三次,处理逻辑用 event.id 做幂等键写 Redis SETNX,数据库里还是建了三条订单,日志里三次都进了创建分支。
一开始怀疑是「处理逻辑先建单后写幂等标记,中间崩溃就是空窗」,查了一圈,方向不对。
把日志和配置对完,能解释这个现象的基本就这几处。幂等键用了 event.id 但 SETNX 的过期时间设成了 0。另一种情况是Redis 连接池切库,不同请求落到不同实例。
还有一种情况,多个 worker 各自读本地缓存判断是否处理过。
动手时先确认幂等键在 Redis 里的实际 TTL
redis-cli ttl idem:evt_1Qx
复现一次看 SETNX 返回值
redis-cli set idem:evt_1Qx 1 nx ex 86400
然后改成先占位再处理并把结果写入幂等记录
python webhook.py --setnx-first --ttl 86400
末了用 stripe 命令行工具重发同一事件验证
stripe trigger payment_intent.succeeded --override event=evt_1Qx
别只看报错消失,验证要多做一步。三次重发只产生一条订单,后两次直接返回已处理,Redis 里幂等键 TTL 为设定的 24 小时。
容易忽略的是,幂等标记必须与业务写入在同一个原子边界内,先建单再打标记,中间任何一次崩溃都会留下重复数据。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。
