Search code examples
javaspring-bootjmsibm-mqspring-jms

Not able to stop an IBM MQ JMS consumer in Spring Boot


I am NOT able to stop an JMS consumer dynamically using a Spring Boot REST endpoint. The number of consumers stays as is. No exceptions either.

IBM MQ Version: 9.2.0.5

pom.xml

<dependency>
    <groupId>com.ibm.mq</groupId>
    <artifactId>mq-jms-spring-boot-starter</artifactId>
    <version>2.0.8</version>
</dependency>

JmsConfig.java

@Configuration
@EnableJms
@Log4j2
public class JmsConfig {
    @Bean
    public MQQueueConnectionFactory mqQueueConnectionFactory() {
        MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
        mqQueueConnectionFactory.setHostName("my-ibm-mq-host.com");
        try {
            mqQueueConnectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
            mqQueueConnectionFactory.setCCSID(1208);
            mqQueueConnectionFactory.setChannel("my-channel");
            mqQueueConnectionFactory.setPort(1234);
            mqQueueConnectionFactory.setQueueManager("my-QM");
        } catch (Exception e) {
            log.error("Exception while creating JMS connecion...", e.getMessage());
        }
        return mqQueueConnectionFactory;
    }
}

JmsListenerConfig.java

@Configuration
@Log4j2
public class JmsListenerConfig implements JmsListenerConfigurer {
    @Autowired
    private JmsConfig jmsConfig;
    private Map<String, String> queueMap = new HashMap<>();

    @Bean
    public DefaultJmsListenerContainerFactory mqJmsListenerContainerFactory() throws JMSException {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setConnectionFactory(jmsConfig.mqQueueConnectionFactory());
        factory.setDestinationResolver(new DynamicDestinationResolver());
        factory.setSessionTransacted(true);
        factory.setConcurrency("5");
        return factory;
    }

    @Override
    public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
        queueMap.put("my-queue-101", "101");
        log.info("queueMap: " + queueMap);

        queueMap.entrySet().forEach(e -> {
            SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint();
            endpoint.setDestination(e.getKey());
            endpoint.setId(e.getValue());
            try {
                log.info("Reading message....");
                endpoint.setMessageListener(message -> {
                    try {
                        log.info("Receieved ID: {} Destination {}", message.getJMSMessageID(), message.getJMSDestination());
                    } catch (JMSException ex) {
                        log.error("Exception while reading message - " + ex.getMessage());
                    }
                });
                registrar.setContainerFactory(mqJmsListenerContainerFactory());
            } catch (JMSException ex) {
                log.error("Exception while reading message - " + ex.getMessage());
            }
            registrar.registerEndpoint(endpoint);
        });
    }
}

JmsController.java

@RestController
@RequestMapping("/jms")
@Log4j2
public class JmsController {
    @Autowired
    ApplicationContext context;

    @RequestMapping(value = "/stop", method = RequestMethod.GET)
    public @ResponseBody
    String haltJmsListener() {
        JmsListenerEndpointRegistry listenerEndpointRegistry = context.getBean(JmsListenerEndpointRegistry.class);

        Set<String> containerIds =  listenerEndpointRegistry.getListenerContainerIds();
        log.info("containerIds: " + containerIds);

        //stops all consumers
        listenerEndpointRegistry.stop(); //DOESN'T WORK :(

        //stops a consumer by id, used when there are multiple consumers and want to stop them individually
        //listenerEndpointRegistry.getListenerContainer("101").stop(); //DOESN'T WORK EITHER :(

        return "Jms Listener stopped";
    }
}

Here is the result that I noticed.

  1. Initial # of consumers: 0 (as expected)
  2. After server startup and queue connection, total # of consumers: 1 (as expected)
  3. After hitting http://localhost:8080/jms/stop endpoint, total # of consumers: 1 (NOT as expected, should go back to 0)

Am I missing any configuration ?


Solution

  • You need to also call shutDown on the container; see my comment on this answer DefaultMessageListenerContainer's "isActive" vs "isRunning"

    start()/stop() set/reset running; initialize()/shutDown() set/reset active. It depends on what your requirements are. stop() just stops the consumers from getting new messages, but the consumers still exist. shutDown() closes the consumers. Most people call stop + shutdown and then initialize + start to restart. But if you just want to stop consuming for a short time, stop/start is all you need.

    You will need to iterate over the containers and cast them to call shutDown().