Activemq version: 5.14.3
Java version 1.7
There are 8 consumers for one queue, messages are stuck in some of the consumers.
In the above image messages are stuck in dispatched queue of first 4 consumer.
Here is my spring configuration file.
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="failover:(tcp://localhost:61616,tcp://localhost:61617)?randomize=false"/>
</bean>
<bean id="cachingFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="connectionFactory"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="defaultDestinationName" value="queue/WebHookProcessingQueue"/>
</bean>
<bean id="myMessageSender" class="com.omoto.jms.sender.MyMessageSender">
<property name="jmsTemplate">
<ref bean="jmsTemplate"/>
</property>
</bean>
<bean id="responseJsonMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="cachingFactory"/>
<property name="destinationName" value="/queue/ResponseJsonProcessingQueue"/>
<property name="concurrentConsumers" value="8"/>
<property name="messageListener" ref="responseJsonServiceListner"/>
</bean>
I am new to activemq, please help me to solve this problem.
We had similar issue with CachingConnectionFactory with DefaultMessageListenerContainer, the issue is resolved after removing the CachingConnectionFactory from DefaultMessageListenerContainer. Alternatively you can disable consumer caching from CachingConnectionFactory . Refer this thread for more info Why DefaultMessageListenerContainer should not use CachingConnectionFactory?.
Related
I'm new in Spring. Recently I do try to make spring batch and spring integration work together. I want to have JobListener which will listen for message comes to specific channel and launch Spring Batch Job.
I found example on github(https://github.com/chrisjs/spring-batch-scaling/tree/master/message-job-launch) and I tried to configure some way copy Spring Batch and Spring Integration together and this looks like:
<!--Incomming channel OneToOne-->
<int:channel id="requests-channel"/>
<!--For multiple consumers OneToMany-->
<int:publish-subscribe-channel id="reply-channel"/>
<!--Channel for file adapter-->
<int:channel id="file-adapter-reply-channel"/>
<int:channel id="statuses">
<int:queue capacity="10"/>
</int:channel>
<int:channel id="jobLaunchReplyChannel"/>
<!--Intercept request-->
<int-http:inbound-gateway request-channel="requests-channel"
supported-methods="PUT"
path="/testData/setProfileDescription"
reply-timeout="30000"
reply-channel="reply-channel">
</int-http:inbound-gateway>
<!--Sending HTTP response back to user OR either 'no reply received within timeout'-->
<bean id="profileDescriptionActivator"
class="ru.tcsbank.service.integrations.activators.ProfileDescriptionActivator"/>
<int:service-activator ref="profileDescriptionActivator"
input-channel="requests-channel"
output-channel="reply-channel"
method="httpMessageActivator"/>
<!--Write profile description to file-->
<bean id="custom-file-name-generator"
class="ru.tcsbank.service.integrations.transformers_generators.ProfilesFileAdapterNameGenerator"/>
<file:outbound-channel-adapter channel="file-adapter-reply-channel"
directory="file:out"
filename-generator="custom-file-name-generator"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" lazy-init="true" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/testdb"/>
<property name="username" value="test_user"/>
<property name="password" value="qwerty123"/>
</bean>
<bean id="stepScope" class="org.springframework.batch.core.scope.StepScope">
<property name="autoProxy" value="true"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="jobRepositoryInDB" class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="transactionManager" ref="transactionManager"/>
</bean>
<bean id="itemProcessor" class="ru.tcsbank.service.batch_processing.CustomItemProcessor"/>
<bean id="itemReader" class="ru.tcsbank.service.batch_processing.CustomReader" scope="step">
<property name="resource" value="classpath:fileOut/*.csv" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="delimiter" value=","/>
<property name="names" value="id,firstName,lastName"/>
</bean>
</property>
<property name="fieldSetMapper">
<bean class="ru.tcsbank.service.batch_processing.ProfileDescriptionLineMapper"/>
</property>
</bean>
</property>
</bean>
<bean id="itemWriter" class="ru.tcsbank.service.batch_processing.CustomWriter"/>
<batch:job id="helloWorldJob" job-repository="jobRepositoryInDB">
<batch:listeners>
<batch:listener ref="jobListener"/>
</batch:listeners>
<batch:step id="step1">
<batch:tasklet>
<batch:chunk reader="itemReader" writer="itemWriter" processor="itemProcessor" commit-interval="10"/>
</batch:tasklet>
</batch:step>
</batch:job>
<int:transformer input-channel="reply-channel" output-channel="file-adapter-reply-channel">
<bean class="ru.tcsbank.service.batch_processing.FileMessageToJobRequest">
<property name="job" ref="helloWorldJob"/>
<property name="fileParameterName" value="input.file.name"/>
</bean>
</int:transformer>
<bean id="jobListener" class="ru.tcsbank.service.batch_processing.CustomJobExecutionListener">
<constructor-arg index="0" ref="notificationSender"/>
</bean>
<batch-int:job-launching-gateway request-channel="reply-channel"
reply-channel="file-adapter-reply-channel"/>
<int:logging-channel-adapter channel="jobLaunchReplyChannel"/>
<int:channel id="notificationsChannel"/>
<int:gateway id="notificationSender"
service-interface="ru.tcsbank.service.batch_processing.NotificationSender"
default-request-channel="notificationsChannel"/>
I expect my helloWorldJob run when(as I understand correctly) my jobListener receives message from notificationsChannel. But it do not work(do not receives message from notificationsChannel) Beyond then it throws error like:
Dispatcher has no subscribers for channel
'application.notificationsChannel'.; nested exception is >org.springframework.integration.MessageDispatchingException: Dispatcher >has no subscribers, failedMessage=GenericMessage [payload=TEST. >Image processing job ran for: 0 minutes, 0 seconds.
It's hard to understand what you would like to achieve with all this custom code, but what I can say, that there is no subscribers for that notificationsChannel in your configuration. You indeed send messages to it via notificationSender gateway, but you don't provide any endpoint to consume that notificationsChannel.
In the sample you mention in the link we have something like this:
<int-jms:outbound-channel-adapter id="notifications" destination-name="notifications"
channel="notificationsChannel"/>
So, messages sent to the notificationsChannel are landed in the notifications queue on JMS broker. Your sample are leaking such a subscriber. Therefore I only can explain a reason of the exception, but definitely can't tell you what do to.
UPDATE
You may not use notificationSender in your solution. Looks like it just a result of the CustomJobExecutionListener. So, if you don't need to listen for job process, just remove that CustomJobExecutionListener and, therefore, this notificationSender declaration together with the notificationsChannel definition.
Everything else you are asking in comments is out of the scope of this SO question. Please, consider to raise those concerns in the separate SO thread.
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 :
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>
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.
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:
Please review the configuration and let me know is there anything else to be changed.
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.
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>
I have a HornetQ server which has topic and queue's. I am not aware of the config on the other side but the way I connect to the Queue is:
<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref ="jndiTemplate"/>
<property name="jndiName" value="ConnectionFactory"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="defaultDestination" ref="destination"/>
<property name="pubSubDomain" value="false"/>
<property name="deliveryPersistent" value="true"/>
<property name="deliveryMode" value="2"/>
</bean>
<bean id="destination" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplate"/>
<property name="jndiName" value="QUEUE_NAME"/>
</bean>
<!-- Listener Asynchronous -->
<bean id="queueListener" class="com.my.queueListener"/>
<jms:listener-container concurrency="5-10">
<jms:listener destination="QUEUE_NAME" ref="queueListener"/>
</jms:listener-container>
I had set the pubSubDomain to true and it worked (strange but true). Anyhow now I want to connect to a topic. I set the pubSubDomain as true and still it gives me an error saying
WARNING: Setup of JMS message listener invoker failed for destination 'Activate_NTD' - trying to recover. Cause: There is no queue with name TOPIC_NAME
I know HornetQ behaves a bit differently as specified here:
exact example for JMS Topic in HornetQ
but I am unable to figure out what to do and how to get this working.
Set the destination-type on the container that defaults to queue, something like
<jms:listener-container destination-type="topic" concurrency="5-10">
<jms:listener destination="TOPIC_NAME" ref="topicListener"/>
</jms:listener-container>
I am using spring Routing data source as explained here and things works well. Now, I want to add connection pooling (Apache DBCP). I changed the basic data source to the connection pool data source. well, It does not work.
On the server start-up I see that connection pooling is happening and I can debug Apache's code, but then, when I am trying to access the DB through my code, I go to the routing data source, and from there to the DriverManager class to get a connection - completely ignoring Apache's code.
<bean id="catalogDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClass}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.pwd}" />
</bean>
<bean id="pool" class="org.apache.commons.pool.impl.GenericObjectPool">
<property name="minEvictableIdleTimeMillis"><value>300000</value></property>
<property name="timeBetweenEvictionRunsMillis"><value>60000</value></property>
</bean>
<bean id="dsConnectionFactory" class="org.apache.commons.dbcp.DataSourceConnectionFactory">
<constructor-arg><ref bean="catalogDataSource"/></constructor-arg>
</bean>
<bean id="poolableConnectionFactory" class="org.apache.commons.dbcp.PoolableConnectionFactory">
<constructor-arg index="0"><ref bean="dsConnectionFactory"/></constructor-arg>
<constructor-arg index="1"><ref bean="pool"/></constructor-arg>
<constructor-arg index="2"><null/></constructor-arg>
<constructor-arg index="3"><null/></constructor-arg>
<constructor-arg index="4"><value>false</value></constructor-arg>
<constructor-arg index="5"><value>true</value></constructor-arg>
</bean>
<bean id="pooledDS" class="org.apache.commons.dbcp.PoolingDataSource" depends-on="poolableConnectionFactory">
<constructor-arg><ref bean="pool"/></constructor-arg>
</bean>
<bean id="routingDataSource" class="something that derived from RoutingDataSource">
<property name="defaultTargetDataSource" ref="pooledDS"/>
<property name="targetDataSources">
<map key-type="java.lang.Integer">
</map>
</property>
</bean>
Can you help me please - what did I do wrong?
Create connection factory where broker url to JVM
<!--tcp://localhost:61616-->
<bean id="connectionFactoryActiveMQ" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost"/>
<property name="useAsyncSend" value="true"/>
</bean>
Create single connection factory becose need one connection
<bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="connectionFactoryActiveMQ"/>
</bean>
create topic destination because need implemented some classes
<bean id="destination" class="org.apache.activemq.command.ActiveMQTopic">
<property name="physicalName" value="TEST"/>
</bean>
Generate jmsTemplate object
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="defaultDestination" ref="destination"/>
<property name="pubSubDomain" value="true"/>
</bean>
My classes who receive messages
<bean id="messageListener1" class="com.aimrposoft.jms.server.Server"/>
<bean id="messageListener2" class="com.aimrposoft.jms.server.Server1"/>
<bean id="messageListener3" class="com.aimrposoft.jms.server.Server2"/>
Generate message class
<bean id="producer" class="com.aimrposoft.jms.client.Producer"/>
<!--<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">-->
<!--<property name="connectionFactory" ref="connectionFactory"/>-->
<!--<property name="destination" ref="destination"/>-->
<!--<property name="messageListener" ref="messageListener1"/>-->
<!--</bean>-->
<jms:listener-container
connection-factory="connectionFactory" destination-type="topic" acknowledge="transacted">
<jms:listener destination="TEST" ref="messageListener1" method="onMessage" subscription="subscription"/>
<jms:listener destination="TEST" ref="messageListener2" method="onMessage" subscription="subscription"/>
<jms:listener destination="TEST" ref="messageListener3" method="onMessage" subscription="subscription"/>
</jms:listener-container>
When I am using vm://localhost message listener don't working correctly, but if I run activeMQ and change broker URL to tcp://localhost:61616, all work is fine.
I think you are missing configuration to start up a embedded broker, can you try adding this to your configuration also:
<amq:broker id="activeMQBroker">
<amq:transportConnectors>
<amq:transportConnector uri="vm://localhost" />
</amq:transportConnectors>
</amq:broker>
amq namespace prefix can be defined this way:
xmlns:amq="http://activemq.apache.org/schema/core"
To further Biju's answer, I use queues not topics, here's my spring config that appears to work just fine (62999 is just a random available port number):
<amq:broker useJmx="false" persistent="false">
<amq:transportConnectors>
<amq:transportConnector uri="tcp://localhost:62999" />
</amq:transportConnectors>
</amq:broker>
<bean id="rawConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localEmbeddedBroker" />
</bean>
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="rawConnectionFactory" />
<property name="sessionCacheSize" value="30" />
<property name="cacheProducers" value="true" />
<property name="cacheConsumers" value="false" />
</bean>