← 返回首页

消息队列重试如何避免重复执行

通过幂等键、重试策略和死信处理,让异步任务可靠落地。

三月第一周,我发错了两张优惠券。

不是手工点错,也不是数据导入错。消费者其实已经处理成功,只是在确认消息时网络抖了一下。队列以为它没做完,又把同一条消息送来一次。程序很勤快,第二张券就这样到了用户账户。

金额不大,教训却很具体:消息队列说“至少送到一次”,就真的可能敲两次门。

先认清是不是同一件事

后来我给每个业务动作加了稳定的幂等键。消费者收到消息后先查处理记录,做过就直接确认;没做过,才在同一事务里完成写入并记上一笔。

这里有个坑:幂等键不能每次重试都随机生成。付款消息用订单号和操作类型组合,优惠券则用活动、用户和发放批次组合。它标识的是那件事,不是那一次发送。

重试也别一窝蜂

网络超时可以等等再试,参数错误却不会因为多试几遍就突然正确。我把错误分成可重试和不可重试两类,间隔逐步拉长,再加一点随机时间,避免故障恢复时一群消息同时撞向下游。

实在处理不了的消息会进入死信队列,原始内容、失败原因和次数都留着。以前告警响完就算结束,现在修复后还能明确地重新投递,并知道是谁在什么时候做了操作。

那两张优惠券最终没有追回,权当交了学费。现在我不再要求异步任务“绝不出错”,只要求它认得旧面孔,跌倒以后也知道怎么回到队伍里。