How to avoid shutdown of SimpleMessageListenerContainer in case of unexpected errors?

谁都会走 提交于 2021-02-07 09:16:08

问题


I am using Java boot 1.4.0 and 'spring-boot-starter-amqp' for connecting to rabbitMq. The message producer, consumer and the rabbitMq server are under my control.Things were working fine for a few months in production. 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. )

Exception log:

2017-02-20 12:42:18.441 ERROR 18014 --- [writeToDBQQueueListenerContainer-17] o.s.a.r.l.SimpleMessageListenerContainer : 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] o.s.a.r.l.SimpleMessageListenerContainer : 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] o.s.a.r.l.SimpleMessageListenerContainer : 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 ...
}

回答1:


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:

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



来源:https://stackoverflow.com/questions/42501328/how-to-avoid-shutdown-of-simplemessagelistenercontainer-in-case-of-unexpected-er

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!