Search code examples
jmsspring-integrationspring-retry

Spring Integration JMS Issue


We are using Spring Integration to consume messages from a queue and the requirement is to send the message to Error queue if there is any issue in the processing of the message consumed. Flow works fine but one issue we see is when there is any exception thrown in processing of message, the message is redirected to the Error queue which we have configured but it is appended by the entire stack trace of the exception. We are looking only for the original message to be delivered to the queue. Below is the configuration we have done,

<bean id="errorQ" class="com.ibm.mq.jms.MQQueue">
    <constructor-arg value="${error.queue}" />
</bean>
<bean id="inQ" class="com.ibm.mq.jms.MQQueue">
    <constructor-arg value="${inbound.queue}" />
</bean>

<int:channel id="error" />
<int:channel id="inbound" />

<int-jms:message-driven-channel-adapter
    id="jmsIn" channel="inbound" container="messageListenerContainer"
    acknowledge="transacted"></int-jms:message-driven-channel-adapter>

<int-jms:outbound-channel-adapter id="jmsError"
channel="error" connection-factory="mqConnectionFactory"
destination="errorQ" delivery-persistent="true"></int-jms:outbound-channel-adapter>


<int:service-activator id="service"
input-channel="inbound" ref="messageListener" method="someMethodInListerner">
    <int:request-handler-advice-chain>
        <ref bean="retryWithBackoffAdviceSession" />
    </int:request-handler-advice-chain>

<bean id="retryWithBackoffAdviceSession"
    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="${initialInterval}" />
                    <property name="multiplier" value="${multiplier}" />
                    <property name="maxInterval" value="${maxInterval}" />
                </bean>
            </property>
            <property name="retryPolicy">
                <bean class="org.springframework.retry.policy.SimpleRetryPolicy">
                    <property name="maxAttempts" value="${redelivery}" />
                </bean>
            </property>
        </bean>
    </property>
    <property name="recoveryCallback">
        <bean
            class="org.springframework.integration.handler.advice.ErrorMessageSendingRecoverer">
            <constructor-arg ref="error" />
        </bean>
    </property>
</bean>

Solution

  • The message sent to the error is an ErrorMessage with payload MessagingException.

    The MessagingException has two properties cause and failedMessage.

    So, if you want to send the original failed message to errorQ, you will need to add a transformer to the error flow...

    <int:transformer ... expression="payload.failedMessage" />
    

    EDIT

    <int:chain input-channel="error">
        <int:transformer expression="payload.failedMessage" />
        <int-jms:outbound-channel-adapter ... />
    </int:chain>
    

    EDIT2

    Generally, when using these techniques, it's useful to convey the reason for the failure. You can add the exception's message as a header...

    <int:chain input-channel="error">
        <int:header-enricher>
            <int:header name="failureReason" expression="payload.cause.message" />
        </int:header-enricher>
        <int:transformer expression="payload.failedMessage" />
        <int-jms:outbound-channel-adapter ... />
    </int:chain>