Conditional retry advice in a Spring Integration m

2019-02-25 17:27发布

问题:

I have a http gateway call that's occasionally returning 503 errors. I'd like to configure retry advice around that call, but I don't want to do it for every error, just the 503s.

<int-http:outbound-gateway ... errorHandler="...">
    <int-http:request-handler-advice-chain>
        <int:retry-advice max-attempts="3" />
    </int-http:request-handler-advice-chain>
</int-http:outbound-gateway>

I already have a custom error handler configured that filters statuses (ex: 404) that I don't want to treat as errors, but I don't see an obvious way to control how the advice is applied based on what I can do in the error handler. This question deals with the same issue, but the answer doesn't explain how to control the advice behavior or reissue the request at the error handler level. Is there a specific exception type to throw?

edit: Example based on answer:

<bean id="spelParser" class="org.springframework.expression.spel.standard.SpelExpressionParser" />

<int-http:outbound-gateway ...>
    <int-http:request-handler-advice-chain>
        <bean class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice">
            <property name="retryTemplate">
                <bean class="org.springframework.retry.support.RetryTemplate">
                    <property name="retryPolicy">
                        <bean class="org.springframework.retry.policy.ExpressionRetryPolicy">
                            <constructor-arg index="0" type="org.springframework.expression.Expression" value="#{spelParser.parseExpression('cause.statusCode.value() == 503')}" />
                            <property name="maxAttempts" value="3" />
                        </bean>
                    </property>
                    <property name="backOffPolicy">
                        <bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
                            <property name="initialInterval" value="1000" />
                            <property name="multiplier" value="2" />
                        </bean>
                    </property>
                </bean>
            </property>
        </bean>
    </int-http:request-handler-advice-chain>
</int-http:outbound-gateway>

回答1:

Well, for the case when you have a HttpServerErrorException but would like to distinguish it by the statusCode from others and don't retry, I would suggest to take a look into the:

 * Subclass of {@link SimpleRetryPolicy} that delegates to super.canRetry() and,
 * if true, further evaluates an expression against the last thrown exception.
 *
 * @author Gary Russell
 * @since 1.2
 *
 */
@SuppressWarnings("serial")
public class ExpressionRetryPolicy extends SimpleRetryPolicy implements BeanFactoryAware {

Where your expression can be like:

expression="statusCode.value() == 503"

UPDATE

Ah! I see. Since ExpressionRetryPolicy uses TemplateParserContext your expression definitely must be like #{statusCode.value() == 503}. But at the same time it is going to be evaluate during bean factory initialization. I suggest you to do something like this:

<bean id="spelParser" class="org.springframework.expression.spel.standard.SpelExpressionParser"/>

and in the ExpressionRetryPolicy bean definition do:

<constructor-arg index="0" type="org.springframework.expression.Expression" 
                 value="#{spelParser.parseExpression('statusCode.value() == 503')}" />

To overcome the collision.