We are using Spring Integration in our project and we have a requirement where If IBM MQ goes down then we will have to auto connect to IBM MQ when it is up. We have done this implementation using recoveryInterval option of org.springframework.jms.listener.DefaultMessageListenerContainer class. We have given recovery interval as 6 seconds so every 6 seconds system try to recover the MQ connection but now we have a requirement where we will have to do the autorecover twice only and after that if still MQ is down then stop the inbound adapter.
Is there any way in Spring Integration to mention the auto recovery retry count so that system will try to recover only for that retry count?
Below is my existing configuration.
<bean id="inQ" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="${mq.inbound.queue}" />
</bean>
<int:channel id="inbound" />
<int-jms:message-driven-channel-adapter
id="jmsIn" channel="inbound" container="messageListenerContainer"
acknowledge="transacted" auto-startup="false">
</int-jms:message-driven-channel-adapter>
<int:service-activator id="mainService"
input-channel="inbound" ref="messageListener" method="onMessage">
<int:request-handler-advice-chain>
<ref bean="retryWithBackoffAdviceSession" />
</int:request-handler-advice-chain>
</int:service-activator>
<bean id="messageListenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="mqConnectionFactory" />
<property name="destination" ref="inQ" />
<property name="sessionTransacted" value="true" />
<property name="maxConcurrentConsumers" value="${maxConcurrentConsumers}" />
<property name="concurrentConsumers" value="${concurrentConsumers}" />
<property name="receiveTimeout" value="${receiveTimeout}" />
<property name="recoveryInterval" value="60000" />
<property name="autoStartup" value="${autoStartup}" />
</bean>
Thanks
Sach
As an alternative to the recoveryInterval, you can now specify a Backoff instead (see the docs).
It doesn't provide a mechanism to stop the container but an appropriate backoff can effectively do what you want.
You would then need to programmatically stop/start to kick it off again.
Related
I have two standalone broker consuming message from another system.
The client consumer uses Camel to consume messages, below is the part of the configuration where it used camel-activemq component.
I am trying to provide both the host information within the borkerURL but throwing some exception.
using jars of
spring-core 4.2.4,
spring-boot: 1.3.1,
activemq-camel: 5.12.1,
activemq-broker: 5.12.1, etc.
...
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="(tcp://host1:61616,tcp://host2:61616)?wireFormat.maxInactivityDuration=500000" />
</bean>
<bean id="jmsPooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" init-method="start" destroy-method="stop">
<property name="maxConnections" value="10" />
<property name="connectionFactory" ref="jmsConnectionFactory" />
</bean>
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="jmsPooledConnectionFactory" />
<property name="concurrentConsumers" value="1" />
<property name="maxConcurrentConsumers" value="1" />
</bean>
<bean id="jms" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsConfig" />
<property name="transacted" value="true" />
</bean>
...
The process throw exception, when i run the camel main with the context.
:PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'brokerURL' threw exception; nested exception is java.lang.IllegalArgumentException: Invalid broker URI: (tcp://host1:61616,tcp://host2:61616)?wireFormat.maxInactivityDuration=500000
Is there any way to pass in the borker URL of two standalone brokers?
If the brokers are part of a failover system, use the "failover" protocol of the ActiveMQ client.
If the brokers have different queues, create two different commponents with different configurations and broker URLs.
refer to jms1 or jms2 in your route.
Searching in the web I found a lot of example of how spring have to be configured (file.xml) for publish/subscriber mode for active MQ but I need how beans need to be configured for Websphere MQ
Anyone have been configured both product with success?
The following is bean definition of a Websphere MQ ConnectionFactory:
<bean id="wmqConnectionFactory" class="com.ibm.mq.jms.MQConnectionFactory">
<property name="queueManager">
<value>QUEUE_MANAGER</value>
</property>
<property name="hostName">
<value>127.0.0.1</value>
</property>
<property name="port">
<value>1414</value>
</property>
<property name="transportType">
<value>1</value>
</property>
<property name="channel">
<value>SYSTEM.DEF.SVRCONN</value>
</property>
</bean>
you may need to provide a username and password, and you can accomplish that by wrapping it in a UserCredentialsConnectionFactoryAdapter:
<bean id="userCredentialsAdapter" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="wmqConnectionFactory" />
<property name="username" value=" " />
<property name="password" value=" " />
</bean>
It is also a good idea to wrap it in a CachingConnectionFactory, so that sessions, consumers and producers are cached, this wrapper also switches the auto-recovery to true:
<bean id="cachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="userCredentialsAdapter"/>
<property name="cacheConsumers" value="true" />
<property name="cacheProducers" value="true" />
<property name="sessionCacheSize" value="10" />
</bean>
with this configuration, you can use the cachingConnectionFactory with whatever bean you need.
jms.brokerurl=failover:(tcp://ip:61616?wireFormat.maxInactivityDuration=0)?jms.prefetchPolicy.queuePrefetch\=2&randomize\=false&initialReconnectDelay\=50&timeout\=3000
Spring configuration
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" init-method="start" destroy-method="stop">
<property name="connectionFactory" ref="jmsConnectionFactory"/>
<property name="maxConnections" value="10"/>
<property name="maximumActive" value="10"/>
<property name="idleTimeout" value="0"/>
</bean>
<bean id="receiveContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
<property name="destination" ref="QUEUE_NAME"/>
<property name="messageListener" ref="productUpdateListener" />
<property name="sessionTransacted" value="true"/>
<property name="autoStartup" value="true"/>
</bean>
PooledConnectionFactory closes sessions/consumer connection after the consumer has processed messages.Hence the consumer count keeps reducing.
If you are using multithreaded environment its better to use CachingConnectionFactory. But this has some drawbacks as it caches the consumers so if a consumer hangs the client would keep pinging the stalled consumer without knowing that its connection is idle.
Exact solution for your problem, using JMS template is hard to find but you can manually create new connections by checking that if a connection has been closed by using connection.start() or connection.createConnection methods.
I have encountered a problem in fetching the messages from Websphere MQ.
We have a application running in spring TC server.
Application is using spring integrator JMS adaptor to receive the messages from Websphere MQ server.
Following is the spring configuration we used.
Problem we are facing is, sometime even though the websphere mq is up and running and application is up and running, the application is not able to fetch the messages so that messages are falling to websphere mq dead letter queue
Is there any possibility for the above scenario? We are not able to reproduce this scenario
<beans:bean id="connectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<beans:property name="transportType">
<util:constant static-field="com.ibm.mq.jms.JMSC.MQJMS_TP_CLIENT_MQ_TCPIP" />
</beans:property>
<beans:property name="queueManager" value="queueManager" />
<beans:property name="hostName" value="hostName" />
<beans:property name="channel" value="channel" />
<beans:property name="port" value="port" />
<beans:property name="clientReconnectOptions">
<util:constant static-field="com.ibm.msg.client.wmq.WMQConstants.WMQ_CLIENT_RECONNECT"/>
</beans:property>
</beans:bean>
<beans:bean id="mqSeriesConnectionFactory" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<beans:property name="username" value="username"/>
<beans:property name="password" value="password"/>
<beans:property name="targetConnectionFactory" ref="connectionFactory"/>
</beans:bean>
<beans:bean id="jmsTransactionManager" class="org.springframework.jms.connection.JmsTransactionManager">
<beans:property name="connectionFactory" ref="mqSeriesConnectionFactory" />
</beans:bean>
<beans:bean id="mqQueueG3Receive" class="com.ibm.mq.jms.MQQueue">
<beans:constructor-arg value="receivequeue" />
<beans:property name="targetClient" value="1"/>
</beans:bean>
<beans:bean id="mqQueueG3Send" class="com.ibm.mq.jms.MQQueue">
<beans:constructor-arg value="sendqueue" />
<beans:property name="targetClient" value="1"/>
</beans:bean>
<jms:message-driven-channel-adapter id="MessageManagerJmsAdapter"
connection-factory="mqSeriesConnectionFactory"
destination="mqQueueG3Send"
concurrent-consumers="7"
max-concurrent-consumers="40"
transaction-manager="jmsTransactionManager"
message-converter="resultMessageConverter"
channel="MessageManagerIncomingChannel" />
<channel id="g3MessageManagerIncomingChannel" />
<service-activator id="MessageManagerActivator"
input-channel="MessageManagerIncomingChannel"
ref="MessageManager"
method="manageMessage" />
Thanks
WebSphere MQ is a little finicky when it comes to Spring Integration JMS. instead of building up the message-driven-channel-adapter with connection settings, you may want to try configuring your own DefaultMessageListenerContainer and using that. things to look out for include;
sessionTransacted = true
transactionManager = [ref]
so this would look like;
<int-jms:message-driven-channel-adapter channel="myChannel" container="myContainer"/>
<bean id="myContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="myConnectionFactory"/>
<property name="destination" ref="myQueue"/>
<property name="sessionTransacted" value="true"/>
<property name="transactionManager" ref="myTransactionManager"/>
</bean>
If they are going to the DLQ it means delivery failed, not that the app could not "fetch the message". I would expect there to be an error logged.
Another thing to look for is if the container's threads (7) are blocked somewhere in your MessageManager bean. Take a thread dump (jstack or visualVM) to find out what the container threads are doing.
Finally, trace logging will show the container thread activity when idle.
I have a spring cxf web service application deployed into a JBOSS server. The service is working fine and once in a while(within 5-6 days after the server start) , I get and error"Could not open JDBC Connection for transaction; nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object" and that particular service goes down
I have around 17 services inside this application and only the service which had this DB connection issue goes down till I restart the server.
Other services are up.
Below is my JDBC template configuration.
<bean id="dataSource" destroy-method="close"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="initialSize" value="10" />
<property name="maxIdle" value="10" />
<property name="maxActive" value="100" />
<property name="maxWait" value="1000" />
<property name="validationQuery" value="select 1 from sysibm.sysdummy1" />
<property name="testOnBorrow" value="true" />
<property name="testWhileIdle" value="true" />
<property name="timeBetweenEvictionRunsMillis" value="1200000" />
<property name="minEvictableIdleTimeMillis" value="1800000" />
<property name="numTestsPerEvictionRun" value="5" />
<property name="defaultAutoCommit" value="false" />
</bean>
Your help is greately appreciated.
I'd recommend that you switch to a JNDI data source managed by JBOSS.
It sounds like either a connection leak or that you have some really long-running processes that hold a database connection long-term, eventually exhausting your connection pool. It's also possible, though unlikely, that you have very high database latency, that a dead connection shows up in the pool, and that recognizing the dead connection, establishing a new one, and validating it takes longer than the 1 second you've given the pool.
You can try and change the datasource to the :
org.springframework.jdbc.datasource.DriverManagerDataSource
It's better to configure a data source with JBoss and do a Java EE-jndi lookup.
http://techdive.in/spring/spring-jndi-datasource-configuration-jboss