INSERT INTO send_lock(biz_no, channel) VALUES ('SO20261113001','sms')
ON CONFLICT DO NOTHING
RETURNING id;
-- 返回 0 行说明已发过 直接跳过
用户反馈一笔订单收到三条一样的短信,时间戳相隔 12 秒和 40 秒。发送日志里三条 message_id 不同,业务单号相同,来源分别是实时、重试、定时补偿。这类现象通常不是突然出现的,往前翻半天日志能看到苗头。
追下去是这么回事:实时发送超时后进了重试队列,定时补偿任务又扫到未确认状态补了一次。三个入口各自判断,没有共享幂等键。发送成功后状态回写慢了半拍,补偿任务就认为没发。
围绕「消息重复发送」排查时,命令行跑一遍比在面板里点十次有用,面板会替你做掉不少隐式操作。权限不要一口气开到最大,先加到够用再往上试,范围小才好收。
处理上按这个顺序:用业务单号加渠道做幂等键 发送前先占位;占位成功才真正发送 失败释放或标记;补偿任务只扫超过阈值仍未成功的记录;状态回写改成发送后立即更新 缩短窗口。
确认没问题再收工,同一订单重复触发五次发送,只产生一条短信记录,用户侧不再收到多余通知。
