简体   繁体   English

如何避免出现意外错误时关闭SimpleMessageListenerContainer?

[英]How to avoid shutdown of SimpleMessageListenerContainer in case of unexpected errors?

I am using Java boot 1.4.0 and 'spring-boot-starter-amqp' for connecting to rabbitMq. 我正在使用Java boot 1.4.0和'spring-boot-starter-amqp'连接到RabbitMq。 The message producer, consumer and the rabbitMq server are under my control.Things were working fine for a few months in production. 消息生产者,消费者和rabbitMq服务器都在我的控制之下。在生产中,几个月后一切正常。 But suddenly my consumer stopped with exceptions given below. 但是突然我的消费者停止了以下例外情况。 As I only produce messages which are always valid, I had no clue what went wrong. 因为我只生成始终有效的消息,所以我不知道出了什么问题。

But this caused my listener-container to shutdown. 但这导致我的监听器容器关闭。 And hence my message processing stopped.I had to manually restart my message-consumer program. 因此,我的消息处理停止了。我不得不手动重新启动我的消息消费程序。

So my questions are: 所以我的问题是:

  1. Can we avoid complete shutdown of listener-container in any unexpected case? 在任何意外情况下,我们都可以避免完全关闭监听容器吗?
  2. Is it possible to gracefully discard such message and keep listener-container alive? 是否可以优雅地丢弃此类消息并使监听器容器保持活动状态?
  3. If not, then are there ways by which I can check if all my listener-containers are running and start them if I found them dead? 如果不是,那么有什么方法可以检查我所有的监听容器是否正在运行,如果发现它们已死,则可以启动它们? ( NOTE: I looked at RabbitListenerEndpointRegistry.getListenerContainers(). But looks like it does not cover SimpleMessageListenerContainer containers. ) (注:我查看了RabbitListenerEndpointRegistry.getListenerContainers()。但看起来它并不涵盖SimpleMessageListenerContainer容器。)

Exception log: 异常日志:

 2017-02-20 12:42:18.441 ERROR 18014 --- [writeToDBQQueueListenerContainer-17] osarlSimpleMessageListenerContainer : Consumer thread error, thread abort. java.lang.NoClassDefFoundError: org/springframework/messaging/handler/annotation/support/MethodArgumentNotValidException at org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler$DefaultExceptionStrategy.causeIsFatal(ConditionalRejectingErrorHandler.java:110) ~[spring-rabbit-1.6.1.RELEASE.jar!/:na] at org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler$DefaultExceptionStrategy.isFatal(ConditionalRejectingErrorHandler.java:97) ~[spring-rabbit-1.6.1.RELEASE.jar!/:na] at org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler.handleError(ConditionalRejectingErrorHandler.java:72) ~[spring-rabbit-1.6.1.RELEASE.jar!/:na] at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeErrorHandler(AbstractMessageListenerContainer.java:625) ~[spring-rabbit-1.6.1.RELEASE.jar!/:na] at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.handleListenerException(AbstractMessageListenerContainer.java:852) ~[spring-rabbit-1.6.1.RELEASE.jar!/:na] at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:685) ~[spring-rabbit-1.6.1.RELEASE.jar!/:na] at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1165) ~[spring-rabbit-1.6.1.RELEASE.jar!/:na] at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:1149) ~[spring-rabbit-1.6.1.RELEASE.jar!/:na] at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1100(SimpleMessageListenerContainer.java:95) ~[spring-rabbit-1.6.1.RELEASE.jar!/:na] at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1312) ~[spring-rabbit-1.6.1.RELEASE.jar!/:na] at java.lang.Thread.run(Thread.java:745) [na:1.8.0_91] Caused by: java.lang.ClassNotFoundException: org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_91] at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_91] at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:89) ~[KattaQueueManager-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_91] ... 11 common frames omitted 

One more exception: 还有一个例外:

 2017-02-20 12:42:18.674 ERROR 18014 --- [imageQueueListenerContainer-53] osarlSimpleMessageListenerContainer : Consumer thread error, thread abort. java.lang.NoClassDefFoundError: com/rabbitmq/utility/Utility at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.checkShutdown(BlockingQueueConsumer.java:348) ~[spring-rabbit-1.6.1.RELEASE.jar!/:na] at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.nextMessage(BlockingQueueConsumer.java:402) ~[spring-rabbit-1.6.1.RELEASE.jar!/:na] at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1160) ~[spring-rabbit-1.6.1.RELEASE.jar!/:na] at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:1149) ~[spring-rabbit-1.6.1.RELEASE.jar!/:na] at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1100(SimpleMessageListenerContainer.java:95) ~[spring-rabbit-1.6.1.RELEASE.jar!/:na] at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1312) ~[spring-rabbit-1.6.1.RELEASE.jar!/:na] at java.lang.Thread.run(Thread.java:745) [na:1.8.0_91] Caused by: java.lang.ClassNotFoundException: com.rabbitmq.utility.Utility at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_91] at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_91] at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:89) ~[KattaQueueManager-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_91] ... 7 common frames omitted 2017-02-20 12:42:18.675 ERROR 18014 --- [imageQueueListenerContainer-53] osarlSimpleMessageListenerContainer : Stopping container from aborted consumer 

My consumer sample code: 我的消费者示例代码:

@Bean
public MessageConverter jsonMessageConverter(){
    //return new JsonMessageConverter();
    Jackson2JsonMessageConverter converter =  new   Jackson2JsonMessageConverter();

    converter.setClassMapper(new ClassMapper() {
        @Override
        public Class<?> toClass(MessageProperties properties) {
            return String.class;
        }

        @Override
        public void fromClass(Class<?> clazz, MessageProperties properties) {
        }
    });

    return converter;
}

@Bean
public ConnectionFactory connectionFactory() 
{
    CachingConnectionFactory connectionFactory =
            new CachingConnectionFactory(_rabbitmqHost, _rabbitmqPort);
    return connectionFactory;
}

@Bean
public RabbitTemplate rabbitTemplate() 
{
    RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());
    rabbitTemplate.setMessageConverter(jsonMessageConverter());
    return rabbitTemplate;
}

@Bean
TopicExchange exchange() 
{
    return new TopicExchange("MyExchange");
}

@Bean
public Queue mainQueue() 
{
    return new Queue("MyMainQ");
}

@Bean
public Binding mainRouteBinding() 
{
    return BindingBuilder.bind(mainQueue()).to(exchange()).with("MyMainQ");
}

@Bean
SimpleMessageListenerContainer mainQueueListenerContainer(
        ConnectionFactory connectionFactory, 
        @Qualifier("mainQueueListenerAdapter") MessageListenerAdapter listenerAdapter) 
{
    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(connectionFactory);
    container.setQueues(mainQueue());

    container.setMessageConverter(jsonMessageConverter());

    container.setMessageListener(listenerAdapter);
    container.setConcurrentConsumers(1);
    return container;
}

@Bean
MessageListenerAdapter mainQueueListenerAdapter(MainConsumer receiver) 
{
    MessageListenerAdapter msgAdapter = new MessageListenerAdapter(receiver, "receiveMessage");

    msgAdapter.setMessageConverter(jsonMessageConverter());

    return msgAdapter;
}

@Bean
MainConsumer getMainConsumer()
{
    return new MainConsumer();
}

//
//The receiving method in MainConsumer class looks as given below
public void receiveMessage(String message) 
{
     // My business logic goes here ...
}

I had the same problems a couple of months ago and this helped me. 几个月前,我遇到了同样的问题,这对我有所帮助。 If the version of your Rabbit Java Client is prior to 4.0.0 you don't have the recovery connection automatically, you need to set, like here: 如果Rabbit Java Client的版本低于4.0.0,则您没有自动的恢复连接,需要进行如下设置:

ConnectionFactory factory = new ConnectionFactory();
factory.setUsername(userName);
factory.setPassword(password);
factory.setVirtualHost(virtualHost);
factory.setHost(hostName);
factory.setPort(portNumber);

// connection that will recover automatically
factory.setAutomaticRecoveryEnabled(true);

// attempt recovery every 10 seconds
factory.setNetworkRecoveryInterval(10000);

Connection conn = factory.newConnection();

Try to check the documentation for RabbitMQ: Rabbit Client API 尝试查看RabbitMQ的文档: Rabbit Client API

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM