1

It is mentioned in the documentation of DefaultMessageListenerContainer class that it is not recommended to use CachingConnectionFactory with dynamic scaling. While searching, I have encountered following link:

Why DefaultMessageListenerContainer should not use CachingConnectionFactory?

Here found a comment from Gary Russell that

the problem is with caching consumers when using variable concurrency in the container; we can end up with a live consumer "stuck" in the cache".

We have used DefaultMessageListenerContainer and CachingConnectionFactory together so this is surely a problem from above link.

We are encountering problems with our application having following behaviour:

  • TCP ZeroWindow network congestion
  • TCP RESET from application server to MQ
  • DB connection grows during the issue while different transactions halt
  • Messages in certain queues gets built up

We have following code configuration :

  1. In ibmmq-context.xml file:

    <!-- WebSphere MQ Connection Factory -->
    <bean id="appMqConnectionFactory" class="com.ibm.mq.jms.MQConnectionFactory">
       <property name="hostName">
           <value>${ibmmq.ip}</value>
       </property>
       <property name="port">
           <value>${ibmmq.port}</value>
       </property>
       <property name="queueManager">
           <value>${ibmmq.queuemanager}</value>
       </property>
       <property name="channel"> 
    <value>${ibmmq.channel}</value> 
    </property>
       <property name="clientReconnectOptions"> 
    <util:constant static-field="com.ibm.msg.client.wmq.WMQConstants.WMQ_CLIENT_RECONNECT"/> 
    </property>
    <property name="transportType" ref="appTransport"/>
    </bean>
    
    <!-- A cached connection  -->
        <bean id="appCachedConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
            <property name="targetConnectionFactory" ref="appMqConnectionFactory"/>
            <property name="sessionCacheSize" value="${jms.session.cachesize}"/>
        </bean>
    
        <!--  Use native MQ classes. -->
    <bean id="appTransport" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
    <property name="staticField">
    <value>com.ibm.mq.jms.JMSC.MQJMS_TP_CLIENT_MQ_TCPIP</value>
    </property>
    </bean>
    
  2. In jms-context file:

    <bean id="bankListener"  class="org.springframework.jms.listener.DefaultMessageListenerContainer">
      <property name="connectionFactory" ref="cachedConnectionFactory" />
      <property name="destination" ref="transactionResponseDestination" />
      <property name="messageListener" ref="thirdpartyService" />
      <property name="autoStartup" value="false"/>
      <property name="taskExecutor" ref="listenerExecutor"/>
      <property name="concurrency" value="20-30"/>
    </bean>
    

There are 6 such listeners like bankListener and each of the listeners has concurrency value, varies from 10-40

<bean id="listenerExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
  <property name="maxPoolSize" value="140"/>
  <property name="corePoolSize" value="100"/>
  <property name="queueCapacity" value="30"/>
  <property name="threadNamePrefix" value="jms-listener-task-"/>
  <property name="threadGroupName" value="jms-listener-tasks"/>
</bean>

and jms-context.xml file uses ibmmq-context.xml file.

  1. And to note, we have used IBM MQ 7.1, Spring 4.2.8, spring-integration-core as 4.3.1.RELEASE and JBoss EAP 6.4.10

We are planning to fix this by following way:

<bean id="bankListener" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
  <property name="connectionFactory" ref="appMqConnectionFactory" />
  <property name="destination" ref="transactionResponseDestination" />
  <property name="messageListener" ref="thirdpartyService" />
  <property name="autoStartup" value="false"/>
  <property name="taskExecutor" ref="listenerExecutor"/>
  <property name="concurrency" value="20-30"/>
</bean>

My request:

  1. Please review the configuration and let me know is there anything else to be changed.

  2. Could you please also explain our application behaviour(above 4 points - a to d) with our current configuration with CachingConnectionFactory and DefaultMessageListenerContainer

Thanks in advance for your help.

JoshMc
  • 10,239
  • 2
  • 19
  • 38
sudipku
  • 11
  • 2

1 Answers1

1

Try setting:

cachingConnectionFactory.setCacheConsumers(false);

Or in Spring it should be:

<bean id="appCachedConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
    ...
    <property name="cacheConsumers" value="false"/>
    ...
</bean>
Eduard
  • 91
  • 2
  • 4