I am using Apache Camel and ActiveMQ in my spring boot application. Sometimes it starts throwing an error that session is closed. I have to restart the application to get rid of this error.
I have gone through some articles which suggest that application is exhausting the max session limit(default 500). Next time when this error will occur I will look into the activemq panel to see active sessions corresponding to a connection.
Here is my configuration file:
<camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring">
<contextScan/>
</camelContext>
<bean class="xy.acb.task.TaskServiceBean">
<property name="camelContext" ref="camelContext"/>
</bean>
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent" destroy-method="shutdown">
<property name="autoStartup" value="true"/>
<property name="connectionFactory">
<bean class="org.apache.activemq.pool.PooledConnectionFactoryBean">
<property name="connectionFactory">
<bean class="org.apache.activemq.spring.ActiveMQConnectionFactory">
<property name="brokerURL"
value="${activemq.brokerURL:tcp://activemq:61616?daemon=true}"/>
</bean>
</property>
</bean>
</property>
<property name="acknowledgementModeName" value="CLIENT_ACKNOWLEDGE"/>
<property name="deliveryMode" value="1"/>
<property name="timeToLive" value="1260000"/>
</bean>
Below is the error trace:
The Session is closed; nested exception is javax.jms.IllegalStateException: The Session is closed
; nested exception is javax.jms.IllegalStateException: The Session is closed
at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:279)
at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:169)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:496)
at org.apache.camel.component.jms.JmsConfiguration$CamelJmsTemplate.send(JmsConfiguration.java:228)
at org.apache.camel.component.jms.JmsProducer.doSend(JmsProducer.java:431)
at org.apache.camel.component.jms.JmsProducer.processInOnly(JmsProducer.java:385)
at org.apache.camel.component.jms.JmsProducer.process(JmsProducer.java:153)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:120)
at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:72)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:416)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:118)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:80)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)
at org.apache.camel.component.direct.DirectProducer.process(DirectProducer.java:51)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)
at org.apache.camel.processor.UnitOfWorkProducer.process(UnitOfWorkProducer.java:74)
at org.apache.camel.impl.ProducerCache$2.doInProducer(ProducerCache.java:375)
at org.apache.camel.impl.ProducerCache$2.doInProducer(ProducerCache.java:343)
at org.apache.camel.impl.ProducerCache.doInProducer(ProducerCache.java:233)
at org.apache.camel.impl.ProducerCache.sendExchange(ProducerCache.java:343)
at org.apache.camel.impl.ProducerCache.send(ProducerCache.java:168)
at org.apache.camel.impl.DefaultProducerTemplate.send(DefaultProducerTemplate.java:119)
at org.apache.camel.impl.DefaultProducerTemplate.send(DefaultProducerTemplate.java:105)
From Activemq 5.7, maximumActive=500(default), is replaced with maximumActiveSessionPerConnection property. Default connections is 8. so totally 500 * 8 = 4000 sessions are allowed. Check which Activemq version you are using and then set the right properties you need to make it work.
Related
My project is using jms+ibmmq to send a message out. it's working properly, and I'm able to push a message to the outbound queue, and then receive a response from the inbound queue. Recently, a client asks if we can send out an alert email if unable to get a response within like 2 min. I checked the spring integration messaging related document, seems gatway can implement it? but still can't get an idea how to use it. can someone help me out?
my current xml configuration
<integration:service-activator id="serviceActivator1" input-channel="inputChannel"
ref="messageProcessService" method="callMsgProcessor" output-channel="requestChannel" />
<bean id="ibmConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory">
<bean class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="transportType">
<util:constant static-field="com.ibm.msg.client.wmq.WMQConstants.WMQ_CM_CLIENT"/>
</property>
<property name="hostName" value="${hostName}"/>
<property name="queueManager" value="${queue-manager}"/>
<property name="channel" value="${channel}"/>
<property name="port" value="${port}"/>
</bean>
</property>
<property name="sessionCacheSize" value="5"/>
</bean>
<bean id="requestQueue" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="${request-queue}"/>
<property name="targetClient">
<util:constant static-field="com.ibm.msg.client.wmq.WMQConstants.WMQ_CLIENT_NONJMS_MQ"/>
</property>
</bean>
<jms:outbound-channel-adapter id="request.queue.adapter" connection-factory="ibmConnectionFactory"
destination="requestQueue" channel="requestChannel"/>
<integration:channel id="requestChannel"/>
<bean id="responseQueue" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="${response-queue}"/>
</bean>
<jms:message-driven-channel-adapter id="responseJMSAdapater"
destination="responseQueue"
channel="responseChannel"
connection-factory="ibmConnectionFactory"
error-channel="errorChannel"
acknowledge="transacted"
/>
<integration:channel id="responseChannel">
<integration:queue capacity="500"/>
<integration:interceptors>
<integration:wire-tap channel="logger"/>
</integration:interceptors>
</integration:channel>
if add a gateway, it looks like
<integration:gateway id="serviceAdaptedGateway" service-interface="com.mycompany.service.gatewayServiceInterface"
default-request-channel="requestChannel"
default-reply-channel="responseChannel"
default-reply-timeout="120000"/>
my question is
seems timeout not working, nothing happen even the waiting time exceed the timeout
although the gateway provide timeout property, where I can add my business logic like send email alert?
My application was running WebSphere where all the connection pool setting was done in WAS console data source and connection pool was handled by IBM WAS. but now i am removing the WAS server and moving to tomcat and using the below connection to connect with Teradatadata source. but getting below error. is there anything i am missing here? or what is properway to create data source using spring xml bean which manage the connections.
ERROR
org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: Connection was closed in SingleConnectionDataSource. Check that user code checks shouldClose() before closing Connections, or set 'suppressClose' to 'true'
CODE
<property name="driverClassName" value="com.teradata.jdbc.TeraDriver"/>
<property name="url" >
<util:constant static-field="MYCLASS._DB_HOST"/>
</property>
<property name="username">
<util:constant static-field="MYCLASS._DB_USER"/>
</property>
<property name="password">
<util:constant static-field="MYCLASS.DB_PWD"/>
</property>
<property name="suppressClose" value="true" />
</bean>```
This is the rabbitmq configuration that I have :
<rabbit:admin connection-factory="rmqConnectionFactory"/>
<bean id="**retryAdvice**" class="org.springframework.amqp.rabbit.config.StatefulRetryOperationsInterceptorFactoryBean">
<property name="retryOperations" ref="retryTemplate"/>
</bean>
<bean id="**retryTemplate**" class="org.springframework.retry.support.RetryTemplate">
<property name="retryPolicy" ref="simpleRetryPolicy"/>
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.FixedBackOffPolicy">
<property name="backOffPeriod" value="5000"/>
</bean>
</property>
<property name="retryContextCache" ref="retryContext"/>
</bean>
<bean id="**retryContext**" class="org.springframework.retry.policy.MapRetryContextCache"/>
<bean id="**simpleRetryPolicy**" class="org.springframework.retry.policy.SimpleRetryPolicy">
<property name="maxAttempts" value="3"/>
</bean>
<!-- Spring AMQP Template -->
<bean id="**rabbitTemplate**" class="org.springframework.amqp.rabbit.core.RabbitTemplate">
<property name="connectionFactory" ref="rmqConnectionFactory"/>
<property name="messageConverter" ref="stdJsonMessageConverter"/>
</bean>
<bean id="**stdJsonMessageConverter**" class="org.springframework.amqp.support.converter.JsonMessageConverter">
<property name="createMessageIds" value="true"/>
</bean>
And my queue is configured as follows :
<rabbit:queue name="${queue}" durable="true">
<rabbit:queue-arguments>
<entry key="x-ha-policy" value="all"/>
</rabbit:queue-arguments>
</rabbit:queue>
<rabbit:direct-exchange name="${exchange}">
<rabbit:bindings>
<rabbit:binding queue="${queue}" key="${routingKey}"/>
</rabbit:bindings>
</rabbit:direct-exchange>
When I published a message on the exchange for the first time, the listener failed with null ID exception. I purged the queue which had the bad message as well. Inspite of that, everytime I start my service, the failed message processing is retried and it fails continuously until there is a RetryCacheCapacityExceeded exception.
Has my failed message been cached somewhere? Is there a way to clear that?
Also, why do retries continue even though my retrytemplate suggest 3 reattempts at that interval of 5 secs?
When you use stateful retry, the retry state for each message id is kept in a cached (so we know when to stop).
If there's no ID, the message will fail (and keep being delivered) unless you add a MissingMessageIdAdvice to the advice chain (before the retry interceptor), which will allow 1 retry for messages with no id.
I can't seem to figure this out...
This works perfectly in JAVA:
// Create a Session
Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); // << means we have to acknowledge that we processed it!
But when I create a Spring Bean, I cannot get the CLIENT_ACKNOWLEDGE to work. It seems that it's auto-acknowledging all messages.
<bean id="testListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer" lazy-init="true">
<property name="connectionFactory" ref="amqConnectionFactory" />
<property name="destinationName" value="MyQueue" />
<property name="messageListener" ref="testListener" />
<property name="autoStartup" value="false"/>
<property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE"/>
<property name="sessionTransacted" value="true"/>
<property name="concurrency" value="2"/>
</bean>
Anything I'm missing?
The DMLC in spring has transactions enabled in your config, while in your Java example, you have transactions disabled. Transactions overrides any acknowledge modes. So, choose if you should go with transactions or client ack since you cannot pick both.
I develop an applivation with very load(request).
I used following technologies in my appliation:
Jpa/Hibernate as persistense layer
Spring and Spring Dao
C3p0 as connection pooling
my problem is : I run my application , when number of request increase, throw exception in
persistense layer that"Cannt open connection"
I increase oracle max session but my problem not solve
I indept in C3p0 document and test its options but my problem not solve.
Thank you for your attention
You increased max sessions on Oracle, but you didn't increase the max size of your connection pool. The exception is telling you that your pool is exhausted. Either find what's holding connections open and get them released sooner, or increase the number of max active connections in the pool.
Is it possible for you to post the Spring configuration for your DataSource. I would expect something like:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="oracle.jdbc.driver.OracleDriver"/>
<property name="jdbcUrl" value="${jdbc.connection.url}"/>
<property name="user" value="${jdbc.connection.username}"/>
<property name="password" value="${jdbc.connection.password}"/>
<property name="initialPoolSize" value="5"/>
<property name="minPoolSize" value="5"/>
<property name="maxPoolSize" value="100"/>
</bean>
With another bean configured where the dataSource is passed by reference:
<bean id="mySampleDao" class="com.example.dao.MySampleDao">
<property name="dataSource" ref="dataSource" />
</bean>
Is this what you have?
What version of Oracle are you using?