RabbitMQ在手动消费的模式下设置失败重新投递策略

最近在写RabbitMQ的消费者,因为业务需求,希望失败后重试一定次数,超过之后就不处理了,或者放入死信队列。我这里就达到重试次数后就不处理了。本来以为很简单的,问了kimi,按它的方法配置之后,发现报错之后一直重复消费,进入了死循环。

下面是kimi给的"最佳实践"的示例代码:

java 复制代码
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistrar;
import org.springframework.amqp.rabbit.listener.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMQConfig {

    @Bean
    public SimpleRabbitListenerContainerFactory myFactory(ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        return factory;
    }
}

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class RabbitMQConsumer {

    @RabbitListener(queues = "your-queue-name", containerFactory = "myFactory")
    public void receiveMessage(final Message message, com.rabbitmq.client.Channel channel) {
        // 消息处理逻辑
        try {
            String payload = new String(message.getBody());
            System.out.println("Received message: " + payload);
            // 业务逻辑处理
            // ...

            // 手动确认消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            System.out.println("Error processing message: " + e.getMessage());
            try {
                // 拒绝消息并重新入队
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
            } catch (Exception ex) {
                // 如果消息拒绝失败,则关闭通道
                channel.close();
            }
        }
    }
}

问题出在哪里呢?

看起来是很完美的,但是......,还是有漏洞:

这样写是有问题的,会导致失败后消息重新入队,应该是因为重新计算重试次数,如果一直失败,就一直重试,一直清空,那永远不能达到最大次数,导致死循环......

所以,这个地方正确的处理方式是抛异常,

直接throw 一个异常即可。这样就能正确重试了。

这个过程参考了这个博文:rabbitmq消费(失败)重试3次(多次) - 幂次方 - 博客园

总结教训:AI不是万能的,如果按AI的方案得不到结果,有可能是它出错了,毕竟它的方案是没有经过实践检验的。这个时候就会发现原始资料的重要性了。博客还是有它存在的价值的。

相关推荐
Flynt19 小时前
Redis Cluster主节点挂了,为什么"高可用"还全员掉线?我把三次kill的记录翻出来了
数据库·redis·分布式
JosieBook21 小时前
【数据库】MySQL 实战精通系列 · 第10篇:分库分表与分布式事务实战
数据库·分布式·mysql
梦帮科技1 天前
vLLM / TensorRT-LLM 极限推理:PagedAttention 细粒度物理页表管理与连续批处理(Continuous Batching)实战
数据结构·人工智能·分布式·python·深度学习·算法·vllm
Frank_refuel1 天前
分布式RPC框架实战(二):服务端模块划分与底层设计
分布式·网络协议·rpc
mftang2 天前
EtherCAT协议:从“飞读飞写”机制到分布式时钟同步的实时以太网架构深度解析
分布式·架构·ethercat·分布式时钟·从站控制器
ShineWinsu2 天前
对于Redis:Hash类型的解析
c++·redis·分布式·缓存·面试·hash·哈希表
东方芷兰2 天前
Agent 技术摘要 03 —— 基座模型、推理模型、Flash、联邦学习、分布式机器学习
人工智能·分布式·机器学习
程序猿乐锅2 天前
【黑马点评 | 第十一篇】关注 Feed 流实现
java·数据库·redis·分布式·后端·缓存·maven
j7~2 天前
【C++标准项目】C++基于protobuf的发布订阅式消息队列(篇一):项目概述+环境搭建
分布式·消息队列·rabbitmq·gtest·protobuf·muduo·sqlites
今年下半年3 天前
【Spring Boot】多种存储文件(FastDFS / MinIO / 阿里云 OSS)接入设计说明(附源码)
spring boot·分布式·中间件·简单工厂模式·策略模式