0

DefaultMessageListenerContainer.shutdown or DefaultMessageListenerContainer.destroy is not removing the consumer from the queue.

Here is a similar post : SpringJMS - How to Disconnect a MessageListenerContainer

(I am not sure how to solve it)

Below is my code :

public class MainProgram {
 private static final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MessageConsumerFacade.class); 
 public static final DefaultMessageListenerContainer container = context.getBean(DefaultMessageListenerContainer.class); 


public static void main(String[] args) throws InterruptedException {
   boolean startListener = isStartListener();   // to start and stop listener at 
    will
   if(startListener){
     if (!container.isRunning()) {
       container.start(); 
     }
   }else{
      if (container.isRunning()) {
         container.stop();
   }
 }
}
}


public class MessageConsumerFacade {
private ConnectionFactory connectionFactory() {
        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
        connectionFactory.setBrokerURL(url);
        connectionFactory.setUserName(userName);
        connectionFactory.setPassword(password);

        RedeliveryPolicy policy = connectionFactory.getRedeliveryPolicy();
        policy.setInitialRedeliveryDelay(30000);
        policy.setRedeliveryDelay(30000);
        policy.setMaximumRedeliveries(2);
        connectionFactory.setNonBlockingRedelivery(true);
        return connectionFactory;
    }

    @Bean
    public MessageListenerContainer listenerContainer() {
        DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
        container.setConnectionFactory(connectionFactory());
        container.setDestinationName(queueName);
        container.setMessageListener(new MessageJmsListener());
        container.setCacheLevel(DefaultMessageListenerContainer.CACHE_NONE);
        container.setErrorHandler(new MessageErrorHandler());
        container.setSessionTransacted(true);
        container.setAutoStartup(false);
        container.shutdown();
        return container;
    }
}


public class MessageJmsListener implements MessageListener {
    
  @Override
    public void onMessage(Message message) {
        if (message instanceof TextMessage) {
            try {
                //process the message and create record in Data Base                
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }     
}


public class MessageErrorHandler implements ErrorHandler {  
    
    @Override
    public void handleError(Throwable t) {
        //log error      
    }
}```

1 Answers1

0

Call shutDdwn() after stop().

See How to pause/resume individual Spring JMS message listeners

(By the way, your call to shutdown() in the bean definition won't do anything since it is not started yet).

Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • Hi Gary Thank you for the response. I looked at the other post you mentioned. In my case I have only one container and the very first time my program runs it creates a new consumer as I can see from Active MQ Console. The challenge I am facing is .... for every new code checked in/ deployed the Main program above is starting another new consumer .... I want to kill the old consumer and start frsh each time my mainprogram restarts/refreshes its context. How can I do this. I tried calling shutdown after stop and initialize before start ... but it didnt help .. I want only 1 clean cosumer always. – sstkoverflowcoder Dec 08 '20 at 18:38
  • `>for every new code checked in/ deployed the Main program above is starting another new consumer` I don't understand - when you redeploy you would normally undeploy the old instance, which would kill the consumer. You should close the application context during shutdown. – Gary Russell Dec 08 '20 at 18:43
  • Hi Gary I am pretty new to spring ... can you please look at the mainprogram above and show me how/where to close the application context correctly ...so that whenever we deploy some new code it closes/kills the previous consumer and start another new consumer cleanly – sstkoverflowcoder Dec 08 '20 at 19:58
  • It's hard to say; your `MainProgram` is not valid Java. It is rather unusual to have the application context stored in a static field. I suggest you search for some Spring tutorials. Consider using [Spring Boot](https://spring.io/projects/spring-boot) for a much easier getting-started experience. Stack Overflow is not the right place to come until you have some basic understanding of Spring. – Gary Russell Dec 08 '20 at 20:11
  • Hi Gary I completely removed AnnotationConfigApplicationContext and I am instead initializing the DefaultMessageListenerContainer without using AnnotationConfigApplicationContext . The problem still exists. So the issue is not with Spring AnnotationConfigApplicationContext but the way the DefaultMessageListenerContainer instance gets killed . The stop and shutdown didnot help. I still end up with old consumer hanging ... and it is never killed. is it cached somehow, this https://stackoverflow.com/questions/48302077/springjms-how-to-disconnect-a-messagelistenercontainer talks about same. – sstkoverflowcoder Dec 08 '20 at 21:40
  • That won't work at all; the container needs to be managed by Spring and you need to shut everything down. You need to explain more about what you mean by "new code checked in" - normally, when you deploy a new version of the application, you undeploy the old version (stop the JVM). It sounds like you are leaving the old one running. – Gary Russell Dec 08 '20 at 22:03
  • Hi Gary I think the problem is with my implementation and understanding of how listener should work. In order for my application to listen to queue continuously I never shutdown listener container. Is this correct way to implement? Should my application start and shutdown listener lets say every 5 seconds. This means every 5 seconds we restart the listener. Is it good way. The only scenario when I stop and shutdown listener is based on business logic. For this I am using a database flag to determine if listener should stop. if the database flag is never set to false I never shutdown listener. – sstkoverflowcoder Dec 09 '20 at 19:40
  • No; you should not stop and start the listener on a chedule; it's still not clear what you are trying to achieve. – Gary Russell Dec 09 '20 at 19:45
  • Gary All I am trying is have listener for ActiveMQ queue using DefaultMessageListenerContainer.To simplify, listener should listen as long as app is running. (for a minute lets forget scenario where we stop listener based on some logic/db flag).The app is a cots product and builds war or resets context behind scenes when we checkin code. Not sure what the mechanism is. It is not a maven project. The problem is whenever code is redeployed, the old consumer is not killed.Thus ending up with a new listener when new code deployed.Is problem with code deploy or I am not closing listener correctly. – sstkoverflowcoder Dec 09 '20 at 22:52
  • Then the problem is with your deployment mechanism. The old app should be shutdown by whatever server you are running it in. – Gary Russell Dec 09 '20 at 22:59
  • Gary....Pls see modified code as well. (Sorry The main program was not valid java . I put in code there to explain the issue).. now it kind of looks like valid java. pls let me know if the code snippet is causing confusion. Thank you so much for your patience and replies. Hope to solve this soon. – sstkoverflowcoder Dec 09 '20 at 23:02
  • Gary ... 2 questions 1)So is it correct to say that container.shutdown() never really needs to be called and whenever jvm stops . it takes care of it and the listener will automatically stop. (2) also looks like every deploy of code is starting new thread or jvm not sure what its called , so I am unable to get a handle of the previous container as it is residing in another jvm.... is that correct. – sstkoverflowcoder Dec 09 '20 at 23:07
  • If it is a war, the application context is usually registered with the web container so it is closed during , this will shut down the container. The JVM doesn’t end in that case. You should look at the spring documentation for information about war deployments and Spring. – Gary Russell Dec 09 '20 at 23:14
  • Hi Gary The problem is with our deployment model since the old app was not being shutdown. This problem is not in higher environments since the old app is always shutdown during deployment. Thanks for all the help. One question... should MessageListenerContainer always be configured as spring bean like below .... so spring manages its lifecycle @Bean public MessageListenerContainer listenerContainer() { is it possbile to get instance of listener like below instead without declaring it as spring bean .DefaultMessageListenerContainer container = new DefaultMessageListenerContainer(); – sstkoverflowcoder Dec 10 '20 at 21:49
  • If it's not managed by Spring (as a bean) then you have to do everything that Spring does to set it up and manage its lifecycle yourself. https://stackoverflow.com/questions/21360550/defaultmessagelistenercontainer-not-receiving-messages/21364885#21364885 – Gary Russell Dec 10 '20 at 22:08