The jdbc inbound channel adapter and message stores in our application consistenly stops querying for data and I've been able to track it down to a blocked Oracle session. In Oracle, we are getting enq: TX - row lock contention. The DBA tracked it down to the following:
SELECT COMPLETE, LAST_RELEASED_SEQUENCE, CREATED_DATE, UPDATED_DATE
from INT_MESSAGE_GROUP
where GROUP_KEY = :1 and REGION=:2
Any suggestions on how to resolve this would be greatly appreciated.
SI configuration (extract):
<int-jdbc:message-store id="jdbc-messageStore" data-source="dataSource" />
<int-jdbc:inbound-channel-adapter id="JDBCInboundChannel" query="${cache.integration.jdbc.selectQuery}"
channel="inboundMessagesChannel" data-source="dataSource" update="update CACHE_REPOSITORY set STATUS='P' WHERE GUID IN (:guid)" row-mapper="rowMapper"
max-rows-per-poll="${cache.integration.jdbc.maxRowsPerPoll}" auto-startup="false" >
<int:poller id="jdbcPoller" fixed-delay="${cache.integration.jdbc.fixedDelay}" >
<int:transactional />
</int:poller>
</int-jdbc:inbound-channel-adapter>
<int:chain...>
<int:aggregator id="reportTypeAggregator" ref="aggregatorBean" method="collect"
message-store="jdbc-messageStore" release-strategy="releaseStrategry"
release-strategy-method="canRelease" correlation-strategy="reportTypeCorrelationStrategry"
correlation-strategy-method="correlate" send-partial-result-on-expiry="true"
expire-groups-upon-completion="true" empty-group-min-timeout="30000" />
</int:chain>
<bean id="queryProvider" class="org.springframework.integration.jdbc.store.channel.OracleChannelMessageStoreQueryProvider"/>
<bean id="jdbc-channel-messageStore" class="org.springframework.integration.jdbc.store.JdbcChannelMessageStore">
<property name="dataSource" ref="dataSource"/>
<property name="channelMessageStoreQueryProvider" ref="queryProvider"/>
<property name="region" value="${cache.integration.channelMessageStore.region}"/>
</bean>
<int:channel id="archiveCreationChannel" >
<int:queue message-store="jdbc-channel-messageStore" />
<int:interceptors>
<int:wire-tap channel="logger" timeout="-1"/>
</int:interceptors>
</int:channel>
<bean id="documentMessageStoreReaper" class="org.springframework.integration.store.MessageGroupStoreReaper">
<property name="messageGroupStore" ref="jdbc-messageStore" />
<property name="timeout" value="${cache.integration.reaper.timeout}" />
<property name="autoStartup" value="false" />
</bean>
<task:scheduled-tasks>
<task:scheduled ref="documentMessageStoreReaper" method="run" fixed-rate="10000" />
</task:scheduled-tasks>
I suppose the main issue is around fixed-rate for documentMessageStoreReaper, which initiate the DELETE from INT_MESSAGE_GROUP. You should change it to the fixed-dealy to avoid concurrent tasks.
Since you say that the DELETE from INT_MESSAGE_GROUP is very long, hence 10 sec between tasks might be not enough.
Related
On Publishing the message to Rabbit MQ Exchange, few of the messages are getting lost. For example, posted 10 messages only five got delivered to the binded queue and the rest 5 messages are lost. Please advice.
Below is Spring XML configuration for connection
<bean id="cachingConnectionFactory" class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory" destroy-method="destroy">
<property name="addresses" value="example.com:8080"/>
<property name="username" value="guest" />
<property name="password" value="guest" />
<property name="virtualHost" value="guest-app" />
<property name="connectionTimeout" value="1000"/>
<property name="cacheMode" value="#{T(org.springframework.amqp.rabbit.connection.CachingConnectionFactory.CacheMode).CONNECTION}"/>
<property name="channelCacheSize" value="6000"/>
<property name="channelCheckoutTimeout" value="60000"/>
<property name="requestedHeartBeat" value="30"/>
<property name="publisherConfirms" value="true"/>
<property name="publisherReturns" value="true"/>
</bean>
Below is Rabbit Template Config
<rabbit:template id="amqpTemplate" connection-factory="cachingConnectionFactory" mandatory="true" retry-template="retryTemplate" />
<bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
<property name="initialInterval" value="500" />
<property name="multiplier" value="10.0" />
<property name="maxInterval" value="10000" />
</bean>
</property>
</bean>
<rabbit:admin connection-factory="cachingConnectionFactory" />
Below is for Publishing message
int:chain input-channel="output">
<int:header-enricher>
<int:header name="amqp_deliveryMode" value="PERSISTENT" type="org.springframework.amqp.core.MessageDeliveryMode"/>
</int:header-enricher>
<int-amqp:outbound-channel-adapter id="outboundAmqp" amqp-template="amqpTemplate" exchange-name-expression="headers['exchange']" routing-key-expression="headers['routingKey']" mapped-request-headers="*" confirm-correlation-expression="payload" confirm-ack-channel="msgResponse" confirm-nack-channel="msgResponse" return-channel="msgResponse"/>
I have a 'datachannel' which gets the result set from DB using inbound-channel adapter.
Here i am getting a field called 'process_id' from DB.After calling an external system through int:http-outbound gateway i am defining a recovery-channel. I want to do an update query only for that process_id.But i am unable to get the process id in the recovery channel.Getting an exception invalid property "payload[process_id]"..Is there anyway to pass the process_id to the recovery channel,so that i can perform my update query in a like this
int-jdbc:outbound-channel-adapter query="update TBL_RECEIPT set receipt_status=1
where process_id in (:payload[process_id])" data-source="dataSource" channel="errors"/>
For clarity,below is spring-integration xml configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:task="http://www.springframework.org/schema/task" xmlns:int-http="http://www.springframework.org/schema/integration/http"
xmlns:stream="http://www.springframework.org/schema/integration/stream"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration-4.1.xsd
http://www.springframework.org/schema/integration/stream
http://www.springframework.org/schema/integration/stream/spring-integration-stream-4.1.xsd
http://www.springframework.org/schema/integration/http
http://www.springframework.org/schema/integration/http/spring-integration-http-4.1.xsd
http://www.springframework.org/schema/integration/jdbc
http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc-4.1.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd">
<int:channel id="requestchannel"></int:channel>
<int:channel id="xtifyrequestchannel"></int:channel>
<int:channel id="xtifyresponsechannel"></int:channel>
<int:channel id="tpgrequestchannel"></int:channel>
<int:channel id="tpgresponsechannel"></int:channel>
<int:channel id="xtifyerrorchannel">
</int:channel>
<int:channel id="tpgerrorchannel">
</int:channel>
<int:channel id="executerchannel">
<int:dispatcher task-executor="taskExecutor" />
</int:channel>
<task:executor id="taskExecutor" pool-size="2" />
<bean id="pollerdatamapper" class="main.java.com.as.poller.PollerDataMapper" />
<bean id="pollerservice" class="main.java.com.as.poller.PollerService" />
<bean id="requestFactory"
class="org.springframework.http.client.SimpleClientHttpRequestFactory">
<property name="connectTimeout" value="10000" />
<property name="readTimeout" value="10000" />
</bean>
<int:logging-channel-adapter id="logger"
level="INFO" />
<int-jdbc:inbound-channel-adapter id="datachannel"
query="select loyalty_id,process_id,mobile_uid,mobile_os from TBL_RECEIPT where r_cre_time=(select min(r_cre_time) from TBL_RECEIPT where receipt_status=0)"
data-source="dataSource" max-rows-per-poll="1" row-mapper="pollerdatamapper">
<int:poller fixed-rate="5000">
</int:poller>
</int-jdbc:inbound-channel-adapter>
<int:gateway id="requestGateway" service-interface="main.java.com.as.poller.RequestGateway"
default-request-channel="requestchannel" default-reply-timeout="20000">
<int:method name="pushNotification" />
<int:method name="sendTPGRequest" request-channel="tpgrequestchannel">
<int:header name="Content-Type" value="multipart/form-data" />
</int:method>
</int:gateway>
<int:object-to-json-transformer
input-channel="requestchannel" output-channel="xtifyrequestchannel"></int:object-to-json-transformer>
<int-http:outbound-gateway id="xtifygateway"
request-channel="xtifyrequestchannel" reply-channel="xtifyresponsechannel" request-factory="requestFactory"
url="${xtifyUrl}" http-method="POST">
<int-http:request-handler-advice-chain>
<int:retry-advice max-attempts="3" recovery-channel="xtifyerrorchannel">
</int:retry-advice>
</int-http:request-handler-advice-chain>
</int-http:outbound-gateway>
<int-http:outbound-gateway id="tpggateway"
request-channel="tpgrequestchannel" reply-channel="tpgresponsechannel"
request-factory="requestFactory" expected-response-type="java.lang.String"
url="${tpg_url}" http-method="POST">
<int-http:request-handler-advice-chain>
<int:retry-advice max-attempts="3" recovery-channel="tpgerrorchannel">
</int:retry-advice>
</int-http:request-handler-advice-chain>
</int-http:outbound-gateway>
<int:json-to-object-transformer
input-channel="tpgresponsechannel" type="main.java.com.as.rest.response.TPGResponse" />
<int:service-activator input-channel="datachannel"
output-channel="executerchannel" ref="pollerservice" method="getRecordFromPoller">
</int:service-activator>
<int:service-activator input-channel="executerchannel"
ref="pollerservice" method="getDataFromExecuterChannel">
</int:service-activator>
<int-jdbc:outbound-channel-adapter
id="tpgsystemfailure"
query="update TBL_RECEIPT set receipt_status=1
where process_id in (:payload.failedMessage.payload[process_id])"
data-source="dataSource" channel="tpgerrorchannel" />
<int-jdbc:outbound-channel-adapter
id="xtifysystemfailure"
query="update TBL_RECEIPT set receipt_status=4 where process_id in (:payload.failedMessage.payload[process_id])"
data-source="dataSource" channel="xtifyerrorchannel" />
<int-jdbc:outbound-channel-adapter
id="xtifysystemsuccess"
query="update TBL_RECEIPT set receipt_status=5 where process_id in (:payload.process_id)"
data-source="dataSource" channel="xtifyresponsechannel" />
</beans>
The recovery-channel gets an ErrorMessage. The payload is a MessagingException with two properties failedMessage and cause.
Use payload.failedMessage.payload[process_id].
While running spring batch job with partition, each of the slave threads are failing with the below error :
[SimpleAsyncTaskExecutor-2] AbstractStep.execute(250) | Encountered an error saving batch meta data. This job is now in an unknown state and should not be restarted.
org.springframework.dao.OptimisticLockingFailureException: Attempt to update step execution id=4623 with wrong version (1), where current version is 2 at org.springframework.batch.core.repository.dao.JdbcStepExecutionDao.updateStepExecution(JdbcStepExecutionDao.java:185) at org.springframework.batch.core.repository.support.SimpleJobRepository.update(SimpleJobRepository.java:171)
Job Repository being used is JobRepositoryFactoryBean. Spring batch version is 2.1.8 .
In BATCH_STEP_EXECUTION table, for all steps the version is 2, even while running the steps for the first time.
Job Configuration as below:
<job id="partitionJob" xmlns="http://www.springframework.org/schema/batch" parent="simpleJob">
<step id="masterStep" xmlns="http://www.springframework.org/schema/batch" parent="skipLimitStep">
<partition step="slave" partitioner="BulkPartitioner" xmlns="http://www.springframework.org/schema/batch">
<handler grid-size="10" task-executor="asyncTaskExecutor" xmlns="http://www.springframework.org/schema/batch" />
</partition>
</step>
</job>
<step id="slave" xmlns="http://www.springframework.org/schema/batch" parent="skipLimitStep">
<tasklet>
<chunk reader="partitionPagingItemReader" writer="partitionItemWriter" commit-interval="1" processor="partitionitemProcessor" skip-limit="1000">
</chunk>
<transaction-attributes propagation="REQUIRES_NEW" />
</tasklet>
</step>
<bean id="BulkPartitioner" class="foo.bar.BulkPartitioner" scope="step" >
<property name="model" value="#{jobParameters['abc']}"/>
</bean>
<bean id="partitionPagingItemReader" class="org.springframework.batch.item.database.JdbcPagingItemReader" scope="step" >
<property name="dataSource" ref="dataSource" />
<!-- <property name="fetchSize" value="#{jobParameters['fetch.size']}"></property> -->
<property name="fetchSize" value="1000"></property>
<property name="queryProvider">
<bean class="org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="selectClause" value="select a, b, c" />
<property name="fromClause" value="from d" />
<property name="whereClause" value="where e= :f" />
<property name="sortKey" value="e" />
</bean>
</property>
<!-- Inject via the ExecutionContext in rangePartitioner -->
<property name="parameterValues">
<map>
<entry key="f" value="#{stepExecutionContext[f]}" />
</map>
</property>
<property name="pageSize" value="1" />
<property name="rowMapper">
<bean class="foo.bar.mapper" />
</property>
</bean>
<bean id="simpleJob"
class="org.springframework.batch.core.job.SimpleJob" abstract="true">
<property name="jobRepository" ref="jobRepository"/>
<property name="restartable" value="true"/>
</bean>
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="databaseType" value="oracle"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="isolationLevelForCreate" value="ISOLATION_DEFAULT"/>
<property name="validateTransactionState" value="false"/>
</bean>
update: This is happening only for failed steps. successful completion of steps are updated correctly.
What could be the cause? TIA.
In case this is a problem for others, this was the solution I found:
<property name="saveState" value="false" />
in the reader(s)/writer(s) for the concurrent job/step. As the logging mentions, "This job is now in an unknown state and should not be restarted" so you should consider:
<property name="restartable" value="false"/>
Sources:
http://docs.spring.io/spring-batch/reference/html/scalability.html
http://docs.spring.io/spring-batch/reference/html/readersAndWriters.html#process-indicator
I am trying to create a generic Error Handling process for All message Handlers that will be used in my SI flow. This will,
1. Retry on Connection Exception.
2. Stop the SI flow using Circuit Breaker.
3. Rollback the failed message to the channel.
I have achieved the Retry and Circuit Break Functionality. But, I am unable to rollback message to the channel.
I tried using transaction advice. But it does not work.
Here is the code.
<bean id="retryAdvice"
class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice">
<property name="retryTemplate">
<bean class="org.springframework.retry.support.RetryTemplate">
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
<property name="initialInterval" value="2000" />
<property name="multiplier" value="2" />
</bean>
</property>
</bean>
</property>
<property name="recoveryCallback">
<bean
class="org.springframework.integration.handler.advice.ErrorMessageSendingRecoverer">
<constructor-arg ref="recoveryChannel" />
</bean>
</property>
<property name="retryStateGenerator">
<bean
class="org.springframework.integration.handler.advice.SpelExpressionRetryStateGenerator">
<constructor-arg value="headers['uniqueId']" />
</bean>
</property>
</bean>
<int:channel id="recoveryChannel" />
<int:transformer id="defaultTransformer" input-channel="recoveryChannel"
output-channel="loggerChannel" ref="defaultTransformer" method="transform">
</int:transformer>
<int:logging-channel-adapter id="loggerChannel"
level="INFO" log-full-message="true" auto-startup="true">
</int:logging-channel-adapter>
<bean id="defaultTransformer"
class="com.bestbuy.ingestion.foundation.core.util.DefaultTransformer" />
<bean id="circuitBreakerAdvice"
class="org.springframework.integration.handler.advice.RequestHandlerCircuitBreakerAdvice">
<property name="threshold" value="2" /> <!-- close after 2 failures -->
<property name="halfOpenAfter" value="60000" /> <!-- half open after 15 seconds -->
</bean>
<tx:advice id="txansactionAdvice" transaction-manager="transactionManager">
</tx:advice>
What type of Transaction Manager I need to use.
I may be using different message Handlers, on different data source.
Here is how I add these advises to the Message Handlers.
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
logger.error("called for bean id :: "+beanName+" with bean class "+bean.getClass().getName());
if(bean instanceof AbstractSimpleMessageHandlerFactoryBean){
logger.error("************ Bean "+beanName+" is instance of AbstractSimpleMessageHandlerFactoryBean **********");
}
if(bean instanceof ConsumerEndpointFactoryBean){
logger.error("Bean is of type ConsumerEndpointFactoryBean");
return populateRequestHandlerAdviceChain((ConsumerEndpointFactoryBean)bean);
}
if(bean instanceof AbstractSimpleMessageHandlerFactoryBean){
logger.error("Bean is of type AbstractSimpleMessageHandlerFactoryBean");
return populateRequestHandlerAdviceChain((AbstractSimpleMessageHandlerFactoryBean<?>)bean);
}
return bean;
}
private Object populateRequestHandlerAdviceChain(ConsumerEndpointFactoryBean bean){
ArrayList<Advice> list = new ArrayList<Advice>();
logger.error("Adding Retry Advice");
list.add((Advice)factory.getBean("retryAdvice"));
logger.error("Adding Cricuit Breaker Advice");
list.add((Advice)factory.getBean("circuitBreakerAdvice"));
logger.error("Adding Transactional Advice");
list.add((Advice)factory.getBean("txansactionAdvice"));
bean.setAdviceChain(list);
return bean;
}
If the bean of type ConsumerEndpointFactoryBean I add these advices. I need transaction management in all these Handlers.
First of all: since your txansactionAdvice is nested to the retryAdvice you rollback here the each retry.
From other side it isn't clear why you apply the circuitBreakerAdvice for each retry. I'd say this patter would be better to use 'around' retryAdvice.
And the txansactionAdvice should on top. So, it might look like this:
txansactionAdvice
circuitBreakerAdvice
retryAdvice
And one more point: your transaction won't be rolled back, bacause your use recoveryCallback, which just sends ErrorMessage and strangles the Exception.
HTH and you'll change your mind on the matter.
As per my understanding, Runtime Exception in ServiceActivator should send message to errorChannel.
But if errorHandler is not set then that doesn't work. I even tried to set errorHandler
<bean id="translatorContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="errorHandler" ref="myErrorHandler"/>
<property name="destination" ref="TRANSLATED-MDCAD" />
<property name="sessionTransacted" value="true" />
<property name="maxConcurrentConsumers" value="50" />
<property name="concurrentConsumers" value="1" />
<property name="receiveTimeout" value="5000" />
<property name="recoveryInterval" value="60000" />
<property name="autoStartup" value="false" />
</bean>
<int:channel id="TRANSLATED-MSG-CHANNEL"/>
<bean id="TRANSLATED-MDCAD" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="TRANSLATED-MESSAGE-QUEUE" />
</bean>
<int-jms:message-driven-channel-adapter
id="MDB-TRANSLATED"
channel="TRANSLATED-MSG-CHANNEL" container="translatorContainer" acknowledge="transacted"/>
<int:service-activator input-channel="IN-MSG-CHANNEL"
output-channel="TRANSLATED-MSG-CHANNEL" ref="myProcess"
method="execute" />
But on RuntimeException in myProcess (ServiceActivator) then i am seeing following in log
WARN : [2014-03-16 00:11:51.219] org.springframework.jms.listener.DefaultMessageListenerContainer - Execution of JMS message listener failed, and no ErrorHandler has been set.
org.springframework.integration.MessagingException: failed to handle incoming JMS Message
at org.springframework.integration.jms.SubscribableJmsChannel$DispatchingMessageListener.onMessage(SubscribableJmsChannel.java:164)
at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:561)
at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:499)
at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:467)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:325)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:263)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1059)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1051)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:948)
at java.lang.Thread.run(Thread.java:662)
I have debugged DefaultMessageListenerContainer, JmsMessageDrivenEndpointParser and some other internal class and found that container is getting set correctly.
BUT when exception is thrown, it is using default container ( not the one i have set on int-jms:message-driven-channel-adapter : translatorContainer which has errorHandler set )
What could be the reason? Is there any other alternate setup I can try to redirect runtime exception to errorChannel? Let me know if you need more information
I am using spring integration version 2.2.5
#### DETAIL CONFIG
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
">
<bean id="connectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="hostName">
<value>${mq_hostname}</value>
</property>
<property name="port">
<value>${mq_port}</value>
</property>
<property name="queueManager">
<value>${mq_queuemanager}</value>
</property>
<property name="channel">
<value>${mq_channel}</value>
</property>
<property name="transportType" value="1" />
<property name="useConnectionPooling">
<value>true</value>
</property>
</bean>
<int:annotation-config />
<int:message-history />
<bean id="defaultMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="destination" ref="DEBATCHED-MDCAD" />
<property name="connectionFactory" ref="connectionFactory" />
<property name="errorHandler" ref="manifestErrorHandler"/>
<property name="sessionTransacted" value="true" />
<property name="maxConcurrentConsumers" value="50" />
<property name="concurrentConsumers" value="1" />
<property name="receiveTimeout" value="5000" />
<property name="recoveryInterval" value="60000" />
<property name="autoStartup" value="false" />
</bean>
</bean>
<bean id="translatorContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="destination" ref="TRANSLATED-MDCAD" />
<property name="connectionFactory" ref="connectionFactory" />
<property name="errorHandler" ref="manifestErrorHandler"/>
<property name="sessionTransacted" value="true" />
<property name="maxConcurrentConsumers" value="50" />
<property name="concurrentConsumers" value="1" />
<property name="receiveTimeout" value="5000" />
<property name="recoveryInterval" value="60000" />
<property name="autoStartup" value="false" />
</bean>
</bean>
<!-- Global Channel Interceptor -->
<int:channel-interceptor ref="metadataInterceptor"
pattern="*CHANNEL" order="1" />
<int:wire-tap pattern="*CHANNEL" order="1" channel="logger" />
<int:gateway id="manifestGateway"
service-interface="gov.dhs.cbp.manifest.oceanexport.gateway.ManifestGateway" error-channel="ERRORS-MSG-CHANNEL" />
<int:logging-channel-adapter id="logger"
level="ERROR" log-full-message="true" />
<int-jms:channel id="INBOUND-MSG-CHANNEL" queue-name="INBOUND" error-handler="manifestErrorHandler"/>
<int:channel id="DEBATCHED-MSG-CHANNEL" />
<bean id="DEBATCHED-MDCAD" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="DEBATCHED" />
</bean>
<int-jms:message-driven-channel-adapter
id="MDB-DEBATCHED"
channel="DEBATCHED-MSG-CHANNEL" container="defaultMessageListenerContainer" acknowledge="transacted"/>
<bean id="manifestErrorHandler" class="gov.dhs.cbp.manifest.process.util.ManifestErrorHandler"/>
<int:channel id="TRANSLATED-MSG-CHANNEL"/>
<bean id="TRANSLATED-MDCAD" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="TRANSLATED" />
</bean>
<int-jms:message-driven-channel-adapter
id="MDB-TRANSLATED"
channel="TRANSLATED-MSG-CHANNEL" container="translatorContainer" acknowledge="transacted"/>
<int:channel id="ERRORS-MSG-CHANNEL" />
<bean id="ERROR-EXTERNAL" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="ERRORS" />
</bean>
<int-jms:outbound-channel-adapter id="ERROR-EXTERNAL-ADAPTER"
channel="ERRORS-MSG-CHANNEL" destination="ERROR-EXTERNAL" />
<int-jms:outbound-channel-adapter id="ERROR-CHANNEL-EXTERNAL-ADAPTER"
channel="errorChannel" destination="ERROR-EXTERNAL" />
<!-- ## Service Activator ## -->
<int:service-activator input-channel="DEBATCHED-MSG-CHANNEL"
output-channel="TRANSLATED-MSG-CHANNEL" ref="manifestProcess"
method="execute" />
<!-- DEBATCHER - SPLITTER -->
<int:splitter input-channel="INBOUND-MSG-CHANNEL"
output-channel="DEBATCHED-MSG-CHANNEL" ref="debatcherService"
method="execute" />
<!-- RESPONSE SERVICE / NOT ROUTER DUE TO BUSINESS LOGIC -->
<int:service-activator input-channel="TRANSLATED-MSG-CHANNEL" ref="responseService"
method="generateResponse"/>
<bean id="pool"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="8" />
</bean>
<!--
<bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
<property name="retryPolicy">
<bean class="org.springframework.retry.policy.SimpleRetryPolicy">
<property name="maxAttempts" value="4" />
</bean>
</property>
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
<property name="initialInterval" <value="1000" />
<property name="multiplier" value="5" />
</bean>
</property>
</bean>
-->
</beans>
USING RETRY template to solve the issue
<bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
<property name="retryPolicy">
<bean class="org.springframework.retry.policy.SimpleRetryPolicy">
<property name="maxAttempts" value="1" />
</bean>
</property>
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
<property name="initialInterval" value="1000" />
<property name="multiplier" value="5" />
</bean>
</property>
</bean>
<int:service-activator input-channel="DEBATCHED-MSG-CHANNEL"
output-channel="TRANSLATED-MSG-CHANNEL" ref="manifestProcess"
method="execute" >
<int:request-handler-advice-chain>
<bean class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice">
<property name="recoveryCallback">
<bean class="org.springframework.integration.handler.advice.ErrorMessageSendingRecoverer">
<constructor-arg ref="errorChannel" />
</bean>
</property>
<property name="retryTemplate" ref="retryTemplate" />
</bean>
</int:request-handler-advice-chain>
</int:service-activator>
As we see by your StackTrace the issue is around SubscribableJmsChannel (<int-jms:channel id="fooChannel" queue-name="foo"/>), where you don't use a custom container.
But you show a config for <int-jms:message-driven-channel-adapter>.
So, be careful analyzing the issue.
Now, if you want the same behaviour for <int-jms:channel/> you can inject your myErrorHandler to the channel's property error-handler