I am using a spring integration chain of service activators to process an incoming message from a queue. One of the service activators messagePersister that persists the incoming message. If this service activator fails, there is a retry advice that tries the operation 3 more times. This part works fine, but if all retries fail, we have a recovery method that persists the message in alternate form (also triggers some notifications etc). This recovery method and the orginal persister method return objects of the same class that then need to be processed by the preprocessor - the next service activator in the chain.
However, it looks like, using the recovery options causes the message to leave the chain, and the return object from the recovery service activator does not go down the chain. Similarly, if the recovery method throws an exception, it does not go to the redboxExceptionChannel which is the exception for the adapter that is listening to the incoming queue.
<int-jms:message-driven-channel-adapter
id="inputChannelAdapter"
connection-factory="jmsConnectionFactory"
destination-name="REDBOX_IN"
channel="redboxIncomingChannel"
max-concurrent-consumers="1"
auto-startup="true"
acknowledge="transacted"
receive-timeout="20000"
error-channel="redboxExceptionChannel"/>
<int:chain id="redboxIncomingChannelProcessingChain"
input-channel="redboxIncomingChannel"
output-channel="redboxOutgoingMessageChannel">
<int:service-activator ref="messagePersister"
method="persistAndAddClientMessageIdToHeader">
<int:request-handler-advice-chain>
<int:retry-advice max-attempts="4" recovery-channel="persistenceRetriesExhaustedChannel" >
<int:exponential-back-off initial="800"
multiplier="3"
maximum="25000"/>
</int:retry-advice>
</int:request-handler-advice-chain>
</int:service-activator>
<int:service-activator ref="redboxPreProcessor" method="validate"/>
<int:service-activator ref="redboxProcessor" method="evaluateRules"/>
</int:chain>
<int:service-activator ref="messagePersister"
method="retriesExhausted" input-channel="persistenceRetriesExhaustedChannel" />
I was expecting the recovery method to be part of the chain that triggered the retries.
The behavior is correct. The
ErrorMessageSendingRecovererhas the logic like this:So, it just does not return. There is no knowledge at that point that your service activator is reply producing.
You can fix the problem this way:
add a
<gateway>at that point and extract your service-activator with retry into an independent component with an input-channel as therequest-channelfrom the mentionedgateway.Then your
messagePersister.retriesExhaustedmust look into aMessagingException.failedMessageto copy its headers before returning from this method. This way thereplyChannelwill be present and endpoint would know where to send a result of your method. ThisreplyChannelis where thatgatewayis waiting for reply. So, you got a normal reply from original service activator and compensation one frompersistenceRetriesExhaustedChannelsubscriber.UPDATE
Regarding errors from the recoverer sub-flow. According to my testing it works as expected:
As you see in the last
retriesExhausted()method I deliberately throw some exception based on the one coming from just failed handler with retry advice.In the end I got logs from that
handleErrors()method like this:(Sorry for Java DSL variant: I haven't worked with XML config for a while).
We might have some difference in the configuration. For example, your
persistenceRetriesExhaustedChannelis not aDirectChannel...