key = 'mail:%s:%s' % (order_no, template)
if redis.set(key, 1, nx=True, ex=86400):
send_mail(order_no, template)
同一笔订单的通知邮件,客户收到两封间隔 40 秒、内容完全一样的邮件,发生在队列重试的那批消息上。先别急着动参数,把报错原文和时间点记下来,顺序反了容易白折腾。
原因不复杂,消费者处理超时后消息被重新投递,幂等键只用了用户 ID,同一个用户的不同邮件互相覆盖又都发出去了。发送动作没有独立去重。
「邮件模板重复投递」排查到最后往往是很小的一处差异,前面那些复杂猜测可以先放一放。动手前把原文件复制一份带时间戳,出问题立刻换回去,比现场分析快得多。
一次只改一处,改完立刻验证,几个改动叠在一起,出问题就说不清是谁导致的。
处理上按这个顺序:幂等键改成业务单号加模板名的组合,一条业务消息只允许发一次;发送前查一次发送记录,命中就跳过并记日志;人为制造一次消费超时,确认重试后只收到一封。
改完只确认一件事:制造重试后收件箱只有一封,日志里能看到一次跳过的记录。
