[英]How can i stop my SimpleMessageListenerContainer from getting stuck in shutdown/restart loop?
I have a SimpleMessageListenerContainer which I am using with RabbitMQ and Java. 我有一个用于RabbitMQ和Java的SimpleMessageListenerContainer。 In most instances I am having no problems, however on some occassions when a message is sent to a queue there appears to be an exception which causes the SMLC to get in a loop trying to shutdown and then restart the queue.
在大多数情况下,我没有问题,但是在某些情况下,将消息发送到队列时,似乎会出现异常,这会导致SMLC陷入尝试关闭然后重新启动队列的循环。
[10/03/15 17:09:38:161 UTC] 00000246 SimpleMessage W org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer run Consumer raised exception, processing can restart if the connection factory supports it.
[10/03/15 17:09:38:161 UTC] 00000246 SimpleMessage W org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer $ AsyncMessageProcessingConsumer run消费者引发的异常,如果连接工厂支持,则处理可以重新启动。 Exception summary: org.springframework.amqp.AmqpIOException: java.io.IOException
异常摘要:org.springframework.amqp.AmqpIOException:java.io.IOException
[10/03/15 17:09:38:189 UTC] 00000246 SimpleMessage I org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer run Restarting Consumer: tag=[null], channel=Cached Rabbit Channel: AMQChannel(amqp://epa_devint1@xx.xx.xx.xx:5782/,1), acknowledgeMode=AUTO local queue size=0
[10/03/15 17:09:38:189 UTC] 00000246 SimpleMessage I org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer $ AsyncMessageProcessingConsumer run重新启动使用者:tag = [null],channel =缓存的兔子频道:AMQChannel(amqp ://epa_devint1@xx.xx.xx.xx:5782 /,1),acceptMode = AUTO本地队列大小= 0
[10/03/15 17:09:39:164 UTC] 00000256 SimpleMessage W org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer run Consumer raised exception, processing can restart if the connection factory supports it.
[10/03/15 17:09:39:164 UTC] 00000256 SimpleMessage W org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer $ AsyncMessageProcessingConsumer run消费者引发的异常,如果连接工厂支持,则处理可以重新启动。 Exception summary: com.rabbitmq.client.ShutdownSignalException: connection error;
异常摘要:com.rabbitmq.client.ShutdownSignalException:连接错误; reason: {#method(reply-code=541, reply-text=INTERNAL_ERROR, class-id=0, method-id=0), null, ""}
原因:{#method(reply-code = 541,Reply-text = INTERNAL_ERROR,class-id = 0,method-id = 0),null,“”}
When i remove the message from the queue through the admin interface then there are no more exceptions. 当我通过管理界面从队列中删除消息时,没有更多例外了。
I believe the cause of the exception is something like a missing header property. 我相信导致异常的原因是缺少标头属性。
What is the proper way to handle this exception such that the message is removed from the queue and the shutdown/restart logic is exited? 什么是处理此异常的正确方法,以便从队列中删除消息并退出关闭/重新启动逻辑?
public SimpleMessageListenerContainer createMessageListenerContainer(Object consumer, String exchangeName, String queueName, String routingKey) {
TopicExchange exchange = new TopicExchange(exchangeName);
Queue queue = new Queue(queueName,
MessagingConstants.RABBIT_MQ_QUEUE_DURABLE,
MessagingConstants.RABBIT_MQ_QUEUE_EXCLUSIVE,
MessagingConstants.RABBIT_MQ_QUEUE_AUTO_DELETE,
MessagingConstants.RABBIT_MQ_QUEUE_ARGUMENTS);
amqpAdmin.declareExchange(exchange);
amqpAdmin.declareQueue(queue);
amqpAdmin.declareBinding(BindingBuilder.bind(queue).to(exchange).with(routingKey));
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
container.setQueues(queue);
container.setConcurrentConsumers(MessagingConstants.RABBIT_MQ_CONCURRENT_CONSUMERS);
container.setErrorHandler(errorHandler);
container.setMessageListener(new MessageListenerAdapter(consumer, null));
container.setAcknowledgeMode(AcknowledgeMode.AUTO);
container.setAdviceChain(retryAdviceChainFactory.createRequestRequeueExceptionAwareRetryChain(MessagingConstants.RABBIT_MQ_RETRY_ATTEMPTS));
container.setChannelTransacted(true);
container.setTaskExecutor(taskExecutor);
container.setTransactionManager(transactionManager);
return container;
}
@Override
public void afterPropertiesSet() {
com.rabbitmq.client.ConnectionFactory rabbitFactory = new com.rabbitmq.client.ConnectionFactory() {
protected void configureSocket(Socket socket) throws IOException {
super.configureSocket(socket);
socket.setSoTimeout(propertiesHolder.getRabbitMQSocketTimeoutMS());
}
};
rabbitFactory.setConnectionTimeout(propertiesHolder.getRabbitMQConnectionTimeoutMS());
rabbitFactory.setRequestedHeartbeat(propertiesHolder.getRabbitMQRequestedHeartbeatInSeconds());
CachingConnectionFactory cachingFactory = new CachingConnectionFactory(rabbitFactory);
cachingFactory.setAddresses(propertiesHolder.getRabbitMQHost());
cachingFactory.setPort(propertiesHolder.getRabbitMQPort());
cachingFactory.setUsername(propertiesHolder.getRabbitMQUsername());
cachingFactory.setPassword(propertiesHolder.getRabbitMQPassword());
cachingFactory.setChannelCacheSize(propertiesHolder.getRabbitMQChannelCacheSize());
connectionFactory = cachingFactory;
retryAdviceChainFactory = new RetryAdviceChainFactory();
amqpAdmin = new RabbitAdmin(connectionFactory);
errorHandler = new ErrorHandler() {
@Override
public void handleError(Throwable e) {
LOG.error("Error occurred", e);
}
};
TopicExchange deadLetterExchange = new TopicExchange(MessagingConstants.RABBIT_MQ_DEAD_LETTER_EXCHANGE);
Queue deadLetterQueue = new Queue(
MessagingConstants.RABBIT_MQ_DEAD_LETTER_QUEUE,
MessagingConstants.RABBIT_MQ_QUEUE_DURABLE,
MessagingConstants.RABBIT_MQ_QUEUE_EXCLUSIVE,
MessagingConstants.RABBIT_MQ_QUEUE_AUTO_DELETE,
MessagingConstants.RABBIT_MQ_QUEUE_ARGUMENTS);
amqpAdmin.declareExchange(deadLetterExchange);
amqpAdmin.declareQueue(deadLetterQueue);
amqpAdmin.declareBinding(BindingBuilder.bind(deadLetterQueue).to(deadLetterExchange).with("#"));
messageRecoverer = new DeadLetterMessageRecoverer(rabbitTemplate(), deadLetterExchange);
}
JDK: 1.6 spring-rabbit: 1.1.3.Release spring-framework: 3.2.1.Release JDK:1.6弹簧-兔子:1.1.3。释放弹簧框架:3.2.1
Your problem is caused by the transactional nature of your message handling. 您的问题是由消息处理的事务性引起的。 I mean this:
我的意思是:
container.setTransactionManager(transactionManager);
What is happening is, that in some cases (probably some issue with message header, as you suggested) you encounter some error, and that is not being handled properly. 发生的情况是,在某些情况下(可能是您建议的消息标题出现问题),您会遇到一些错误,并且无法正确处理。 The error propagates through and reaches the txManager, which in turn:
该错误通过txManager传播并到达txManager,后者依次为:
Now this behavior above absolutely makes sense when you had an issue which is not a direct consequence of your message. 现在,当您遇到的问题并非消息直接导致的时候,上述行为绝对有意义。 Let's say you encountered a timeout while processing the message;
假设您在处理邮件时遇到超时; the application was shutting down while processing it;
该应用程序正在处理时正在关闭; in all these cases redelivering the message later OR to another node does make sense.
在所有这些情况下,稍后再传递消息或将消息重新传递到另一个节点确实有意义。
In your case however does not matter when and does not matter which node receives the faulty message, you will get the same problem, and you need manually delete that message. 但是,对于您而言,无论何时接收哪个节点都无所谓,也有问题,您将遇到相同的问题,并且需要手动删除该消息。 In order to avoid this situation you can:
为了避免这种情况,您可以:
programmatically filter out invalid messages and do not return them to the queue either by 以编程方式过滤掉无效消息,并且不要通过以下方式将它们返回到队列中
use RabbitMQ features to deal with errors depending on your requirements 根据您的需求使用RabbitMQ功能处理错误
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.