Search code examples
spring-mvcibm-mqspring-jmsmessage-listener

Switch on/off IBM MQ listener based on flag from DB


This is an existing monolith app and fix is required without a drastic change of the setup.

Project setup: project 1 (config) - > where all mq-xml files are present (e.g - ibm_mq_config.xml)

e.g - content of dev_bm_mq.xml

${hname} ${port} ${qmgr} 1

<!-- JMS Queue Connection Factory -->
<bean id="jmsQueueIdsConnectionFactory"
    class="org.springframework.jms.connection.SingleConnectionFactory">
    <property name="targetConnectionFactory">
        <ref bean="mqIdsConnectionFactory" />
    </property>

</bean>


<!-- JMS Destination Resolver -->
<bean id="jmsDestinationResolver"
    class="org.springframework.jms.support.destination.DynamicDestinationResolver">
</bean>


<!-- JMS Queue Template -->
<bean id="jmsQueueIdsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory">
        <ref bean="jmsQueueIdsConnectionFactory" />
    </property>
    <property name="defaultDestinationName">
        <value>${myQUEUE}</value>
    </property>
    <property name="pubSubDomain">
        <value>false</value>
    </property>
    <property name="receiveTimeout">
        <value>20000</value>
    </property>
</bean>  

<bean id="jmsContainer"
    class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="jmsQueueConnectionFactory" />
    <property name="destinationName">
        <value>${myQUEUE}</value>
    </property>
    <property name="messageListener" ref="simpleMessageListener" />
    <property name="concurrentConsumers" value="2" />
    <property name="maxConcurrentConsumers" value="3" />
    <property name="idleTaskExecutionLimit" value="4" />
    <property name="maxMessagesPerTask" value="4" />
    <property name="receiveTimeout" value="5000" />
    <property name="recoveryInterval" value="5000" />
    <property name="sessionTransacted" value="true" />
</bean> 

****Project B (App)****

loads the spring xml from project config as below: WebContent/WEB-INF/spring/sprint-context.xm

<import resource="classpath*:com/my/package/${config.env}-${config-broker}.mq.xml"

public class TestMessageListener implements MessageListener {

        public void onMessage(Message message) {
          //process the message
      }
    }

When the server starts up, it's able to start the server and setup the listener without any issues.

Issue with the above setup : When we scale the app horizontally (add few nodes ), it's gives max channel issues which I am trying to solve.

Requirement: based on a DB table I want to turn off the mq listener on few nodes on the fly. or when I horizontally scale the app.

e.g - Table:mq-config

|host|broker|flag
-----------------------------
|qa5|ibm|false
|qa2|ibm|true

So, I want mq listener on qa5 not to start and qa2 to start and listen to the Queue. Also, I want to stop/start listener on the fly (just by updating the DB)

Question - Any thoughts on how do I achieve the above use case without re-writing the entire setup.


Solution

  • Inject the listener container (e.g. @Autowired).

    Then

    jmsContainer.stop();
    jmsContainer.shutdown();
    
    ...
    
    jmsContainer.initialize();
    jmsContainer.start();
    

    You can also set the autoStartup property to false to prevent the container from starting during application initialization (but don't call initialize() before the first start() - only after calling shutdown().