2
votes

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>
1

1 Answers

2
votes

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