springBoot-rabbit MQ-设置手动确认ACK-Channel shutdown异常

/ MQJava / 没有评论 / 4698浏览

记一次 springBoot + rabbitMQ设置手动ACK时的异常,配置文件设置了

//表示启动消费方的手动确认
spring.rabbitmq.listener.simple.acknowledge-mode=manual

但手动ACK没有生效,代码接收消息后,当业务完毕,执行:

//确认消息已经被消费
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

异常为:

2018-11-05 17:33:33.090 [ERROR] [AMQP Connection 59.110.229.19:5672] Caller+0     at org.springframework.amqp.rabbit.connection.CachingConnectionFactory$DefaultChannelCloseLogger.log(CachingConnectionFactory.java:1199)
Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - unknown delivery tag 1, class-id=60, method-id=80)
2018-11-05 17:33:34.081 [WARN ] [SimpleAsyncTaskExecutor-2] Caller+0     at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.logConsumerException(SimpleMessageListenerContainer.java:1462)
Consumer raised exception, processing can restart if the connection factory supports it
com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - unknown delivery tag 1, class-id=60, method-id=80)
    at com.rabbitmq.client.impl.ChannelN.asyncShutdown(ChannelN.java:484)
    at com.rabbitmq.client.impl.ChannelN.processAsync(ChannelN.java:321)
    at com.rabbitmq.client.impl.AMQChannel.handleCompleteInboundCommand(AMQChannel.java:144)
    at com.rabbitmq.client.impl.AMQChannel.handleFrame(AMQChannel.java:91)
    at com.rabbitmq.client.impl.AMQConnection$MainLoop.run(AMQConnection.java:560)
    at java.lang.Thread.run(Thread.java:748)
2018-11-05 17:33:34.082 [INFO ] [SimpleAsyncTaskExecutor-2] Caller+0     at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1453)
Restarting Consumer: tags=[{amq.ctag-zms15dchTPRiv8SH2W0_8Q=videoChange}], channel=Cached Rabbit Channel: AMQChannel(amqp://admin@59.110.229.19:5672/,2), conn: Proxy@131c5bd Shared Rabbit Connection: SimpleConnection@3a500321 [delegate=amqp://admin@59.110.229.19:5672/, localPort= 50032], acknowledgeMode=AUTO local queue size=0

体现重点的有两条:

1、com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - unknown delivery tag 1, class-id=60, method-id=80)

表明这条消息对于MQ来说没找到,重点是这个---unknown delivery tag 1-参考rabbitMQ的tag机制可知这条消息已经完成了消费。

2、Restarting Consumer: tags=[{amq.ctag-zms15dchTPRiv8SH2W0_8Q=videoChange}], channel=Cached Rabbit Channel: AMQChannel(amqp://admin@59.110.229.19:5672/,2), conn: Proxy@131c5bd Shared Rabbit Connection: SimpleConnection@3a500321 [delegate=amqp://admin@59.110.229.19:5672/, localPort= 50032], acknowledgeMode=AUTO local queue size=0

表明这条消息被一个设置为自动确认的任务(至于他具体是啥,怎么执行的,没深入看源码,等大神给解释了。)给确认了。

各种百度,发现MQ配置的时候,如果配置了json解析器。如下:

@Bean
public MessageConverter messageConverter() {
    return new ContentTypeDelegatingMessageConverter(new Jackson2JsonMessageConverter());
}

则程序会走自动确认消费,配置文件的配置就不生效了(这个不知道为什么,也可能springboot中某些配置的先后顺序的问题)

这个问题解决办法就是重写一下这个东东,用代码设置手动确认。就OK了

@Bean
public RabbitListenerContainerFactory<?> rabbitListenerContainerFactory(
    ConnectionFactory connectionFactory){
    SimpleRabbitListenerContainerFactory factory = 
        new SimpleRabbitListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    factory.setMessageConverter(new Jackson2JsonMessageConverter());
    factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);             
    return factory;
}