I have configured (with spring) my application to listen to a jms que with activemq, and everything works fine.
My activemq server is installed on another server and sometime it can go offline and I would like to handle the connection error. Is that possible?
Here is my spring configuration
<amq:connectionFactory id="jmsFactory" brokerURL="tcp://xxx.xxx.xxx.xxx:61616" />
<bean id="messageConverter" class="com.unic.thesting.main.jms.message.TheStingMessageConverter" scope="tenant"/>
<jms:listener-container concurrency="10" connection-factory="thestingJmsFactory" destination-type="queue" message-converter="thestingMessageConverter">
<jms:listener destination="in" ref="orderStatusConsumer" method="consume"/>
</jms:listener-container>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate" scope="tenant">
<property name="messageConverter" ref="messageConverter" />
<property name="connectionFactory">
<bean class="org.springframework.jms.connection.SingleConnectionFactory" scope="tenant">
<property name="targetConnectionFactory">
<ref local="jmsFactory" />
</property>
</bean>
</property>
</bean>
The DefaultMessageListenerContainer which gets registered when you use ` handles recovering connections to the JMS provider if it gets dropped for any reason (it by default retries every 5 seconds until the connection is restored), so you don't have to do anything on the listener front.
On the sending side with jmsTemplate, you would receive a runtime org.springframework.jms.JmsException if there is any issues in sending a message. You should be able to catch it for any custom processing
Related
We have a Spring based web application deployed in Tomcat. The web application uses Spring's JmsTemplate and DefaultMessageListenerContainer to produce and consume messages respectively. Our JMS provider is ActiveMQ "Classic" and we have used ActiveMQ client libraries to establish a connection with the native broker. We have used PooledConnectionFactory from the activemq-pool library. Since it's a Spring web application we have defined the connection factory bean and wired the connectionFactory into JmsTemplate and DefaultMessageListenerContainer beans respectively. We are assuming the pooling would be driven by Spring through the connection factory.
The behavior we are seeing is the JMS sessions are being created/destroyed continuously. Under load the application would stop consuming the messages.
After reading different articles we are trying to understand the role of JCA JMS. Can anybody suggest implementing JMS through JCA would resolve the issue and to enlist JMS as an XA resource to maintain the connections and sessions through JCA Adapters.
In our Spring JMS web application and Tomcat server we have used both the ActiveMQ PooledConnectionFactory and ActiveMQConnectionFactory from ActiveMQ client libraries. We see the sessions are being created/destroyed frequently and this stops the JMS client from consuming messages.
The below snippet of the Spring beans how we have configured the Spring JmsTemplate and DefaultMessageListenerContainer beans wired in with the connectionFactory.
<!--bean id="jmsQueueConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="ssl://localhost:61616"/>
<property name="trustAllPackages" value="true"/>
</bean-->
<bean id="jmsQueueConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="ssl://localhost:61616"/>
<property name="trustAllPackages" value="true"/>
</bean>
</property>
<property name="maxConnections" value="5"/>
<property name="maximumActiveSessionPerConnection" value="400"/>
</bean>
<bean id="dmDefaultMessageListenerContainer" class="com.crsoftwareinc.crs.core.jmsListener.DMDefaultMessageListenerContainer">
<property name="autoStartup" value="false"/>
<property name="concurrentConsumers" value="1" />
<property name="maxConcurrentConsumers" value="5" />
<property name="cacheLevelName" value="CACHE_NONE"/>
<property name="connectionFactory" ref="jmsQueueConnectionFactory" />
<property name="sessionTransacted" value="true"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="jmsQueueConnectionFactory"/>
<property name="sessionTransacted" value="true"/>
</bean>
We are looking for a work around how could we use JMS with ActiveMQ in Spring Web application in production deployments where the connections and sessions are maintained seamlessly?
In order to perform parallel processing of jms messages, I have configured the JmsComponent and connectionFactory as below.
After reading some posts and the official tutorial, seems that the below configuration should work for ActiveMQ. However, my testing shows that it doesn't work on Solace. Can someone give me a hint on this? Thanks.
// Route Definition - Camel Java DSL
from(INBOUND_ENDPOINT).setExchangePattern(ExchangePattern.InOnly).threads(5).bean(ThroughputMeasurer.class);
<!-- JMS Config -->
<bean id="jms" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="cachedConnectionFactory" />
<property name="acknowledgementModeName" value="AUTO_ACKNOWLEDGE" />
<property name="deliveryPersistent" value="false" />
<property name="asyncConsumer" value="true" />
<property name="concurrentConsumers" value="5" />
</bean>
<!-- jndiTemplate is omitted here -->
<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplate" />
<property name="jndiName" value="ceConnectionFactory" />
</bean>
<bean id="cachedConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="connectionFactory" />
<property name="sessionCacheSize" value="30" />
</bean>
I believe the problem here is that your consumer is bound to an exclusive queue, and only 1 consumer is allowed to process message. Binding to an non-exclusive queue should solve the problem.
Exclusive queues only allow the first consumer to consume from the queue.
All other consumers that are bound to the queue will not receive data. In the event that the first consumer disconnects, the next oldest consumer will begin receiving data. The other consumers can be thought of as being "standby" consumers that will take over the moment the first consumer disconnects.
Non-exclusive queues are used for load balancing. Messages that are spooled to the queue will be distributed to all consumers in a round-robin manner.
Check:
Are there any exception messages in the log?
Is the jndiName correct? Perhaps it should be jms/ceConnectionFactory?
Is the URI INBOUND_ENDPOINT correct?
...
Try to setup ActiveMQ first, and migrate the configuration to Solace.
I have a use case where I want to create multiple listeners(6) in an application. I want to subscribe to multiple destinations(6 topics). All the subscription are durable. I am using separate default message listener container(DMLC) for each listener and using different client id but I am confused about how connection factory should be used.
Should I use single ActiveMQ pooled connection factory with maxConnection specified to 6. OR should I use different pooled connection factory for each listener ?
Is there any harm is using pooledConnectionFactory with maxConnection for durable subscriber?
Source code:
Connection Factory:
<bean id="jmsFactory" class="org.apache.activemq.pool.PooledConnectionFactory"
destroy-method="stop">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL">
<value>${jms.broker.url}</value>
</property>
</bean>
</property>
<property name="maxConnections" value="6" />
and my listener is using it as: (I have 6 similar listeners similar to this using different destinations and client ID)
<bean id="listenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer"
<property name="connectionFactory" ref="jmsFactory" />
<property name="destination" ref="topic_pnlCompleteTopic" />
<property name="durableSubscriptionName" value="FAGCompletion" />
<property name="pubSubDomain" value="true" />
<property name="subscriptionDurable" value="${jms.fagsListener.durable}" />
<property name="clientId" value="${jms.fagsListener.clientId}" />
<property name="messageListener" ref="pnlMessageListener" />
<property name="messageSelector" value="JMSType = 'FAG Completion'" />
</bean>
That sounds all fine to me as long as you're not using this connection factory for something else. There is no reason to limit the number of connections to 6, you can put a higher number if you want and it will be only used if necessary. ConnectionFactory is typically the thing that you share for your whole app. See it as a kind of DataSource for JMS access
You listeners will typically only use one session each, since you are using topics. There is no reason to specify a limit on your pool, or to use multiple pools. You typically use one pooled connection factory for your application unless you see a real reason to limit or split it up into different pools.
I have the following AMQ consumer configuration file which tries to consume 'persistent' messages from the queue. Also, the messages are 'transacted' (as I need to rollback if a message can't be processed in an expected way).
I see a problem with this configuration:
Whenever the consumer calls session.commit() after consuming the message, I see the commit call taking ~8 seconds to come out. I believe this is not expected.
Can someone point me if I have any issues with the below config?
<bean id="amqConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
</bean>
<bean id="simpleMessageListener" class="listener.StompSpringListener" scope="prototype" />
<bean id="destination" class="org.apache.activemq.command.ActiveMQQueue">
<property name="physicalName" value="JOBS.notifications"/>
</bean>
<bean id="poolMessageListener" class="org.springframework.aop.target.CommonsPoolTargetSource">
<property name="targetBeanName" value="simpleMessageListener"/>
<property name="maxSize" value="200"/>
</bean>
<bean id="messageListenerBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource" ref="poolMessageListener"/>
</bean>
<jms:listener-container
container-type="default"
connection-factory="amqConnectionFactory"
acknowledge="transacted"
concurrency="200-200"
cache="consumer"
prefetch="10">
<jms:listener destination="JOBS.notifications" ref="messageListenerBean" method="onMessage"/>
</jms:listener-container>
Take a look at the the ActiveMQ Spring support page. What I can see immediately is that you should be using a PoolingConnectionFactory instead of an ActiveMQConnectionFactory. This will ensure that only a single TCP connection is set up to the broker from your code, and will be shared between polling threads.
I am using ActiveMQ implementation for sending messages to the queue. When there is a problem in the queue I am redirecting all my messages to another queue using failover mechanism.
But my requirement is that the failover queue messages should not be consumed by the consumer until the the messages in the first queue are consumed by the consumer.
Can anyone suggest me how to implement this scenario? Thanks in advance.
Here is my XML configuration:
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://172.16.121.146:61617" />
</bean>
<bean id="cscoDest" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="STOCKS.CSCO" />
</bean>
<!--The message listener-->
<bean id="portfolioListener" class="my.test.jms.Listener"></bean>
<!--Spring DMLC-->
<bean id="cscoConsumer" class="org.springframework.jms.listener.DefaultMessageListenerContainer102">
<property name="connectionFactory" ref="jmsConnectionFactory" />
<property name="destination" ref="cscoDest" />
<property name="messageListener" ref="portfolioListener" />
<property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE"/>
</bean>
<!--Spring JMS Template-->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="jmsConnectionFactory" />
</bean>
<bean id="stockPublisher" class="my.test.jms.SpringPublisher">
<property name="template" ref="jmsTemplate" />
<property name="destinations">
<list>
<ref local="cscoDest" />
</list>
</property>
</bean>
The ActiveMQ failover mechanism is there to let the client fail over to another ActiveMQ broker if the connection with the current broker goes down.
Your requirement that the 2nd queue should not deliver messages until the first queue is empty is very odd. What happends if someone terminates the ActiveMQ server by pulling the plug? There might still be unprocessed messages on that server, but you cannot process them.
What you want is a master slave setup that shares a disk area (network share somewhere). Then a second broker can pick up where the master broker stopped working.