Spring Retry: NeverRetryLogic не работает, как я ожидал, с ExceptionClassifierRetryPolicy

Я работаю в сценарии повторной попытки (связанном с исходящим шлюзом http). Логика повтора работает очень хорошо, но моя логика отказа от повтора выглядит как ошибка.

Что я хотел бы сделать, так это не повторять попытку, если я получу ошибку статуса http, отличную от 404 500 503 504.

Чтобы проверить это, у меня есть настраиваемая конечная точка, которую я могу настроить для ответа с любой ошибкой состояния http в течение X раз, прежде чем добиться успеха.

Так, например, я могу настроить свою конечную точку так, чтобы она получала статус http 400 только при первом нажатии, и после этого, когда я повторю попытку, я получу успешный ответ.

Тем не менее, я ожидал, что когда я настрою свою конечную точку для получения статуса http 400 только в первый раз, это никогда не будет повторяться, но похоже, что это не работает.

Логика, которая у меня есть для сценария «никогда не повторять», такова:

   <int-http:outbound-gateway
            header-mapper="httpHeaderMapper"
            request-channel="some_request_channel"
            url-expression="'http://some_url"
            http-method="POST"
            expected-response-type="java.lang.String"
            charset="UTF-8"
            reply-timeout="${com.property.value.from.db.for.time.out:5000}"
            reply-channel="some_reply_channel">

            <int-http: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-http:request-handler-advice-chain>

    </int-http:outbound-gateway>


    <bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
        <property name="retryPolicy">
            <bean class="com.whatever.CustomRetryPolicy">
                <property name="maxAttempts" value="${com.property.value.from.db.for.retry.MaxAttemps:5}" />
            </bean>
        </property>
        <property name="backOffPolicy">
            <bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
                <property name="initialInterval" value="${com.property.value.from.db.for.backoffpolicy.initialInterval:1000}" />
                <property name="multiplier" value="${com.property.value.from.db.for.backoffpolicy.initialInterval:6}" />
            </bean>
        </property>
    </bean> 

CustomRetryPolicy такова:

public class CustomRetryPolicy extends ExceptionClassifierRetryPolicy {

    private String maxAttempts;

    @PostConstruct
    public void init() {

        final RetryPolicy defaultRetry = defaultRetryPolicy();
        this.setExceptionClassifier(new Classifier<Throwable, RetryPolicy>() {
            @Override
            public RetryPolicy classify(Throwable classifiable) {
                Throwable exceptionCause = classifiable.getCause();
                if (exceptionCause instanceof HttpStatusCodeException) {
                    int statusCode = ((HttpStatusCodeException) classifiable.getCause()).getStatusCode().value();
                    handleHttpErrorCode(statusCode);
                }
                return defaultRetry;
            }
        });
    }

    public void setMaxAttempts(String maxAttempts) {
        this.maxAttempts = maxAttempts;
    }


    private RetryPolicy handleHttpErrorCode(int statusCode) {
        RetryPolicy retryPolicy = null;
        switch(statusCode) {
        case 404 :
        case 500 :
        case 503 :
        case 504 :
            retryPolicy = defaultRetryPolicy();
            break;
        default :
            retryPolicy = neverRetry();
            break;
        }

        return retryPolicy;
    }

    private RetryPolicy neverRetry() {
        return new NeverRetryPolicy();
    }

    private RetryPolicy defaultRetryPolicy() {
        final SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy();
        simpleRetryPolicy.setMaxAttempts(5);
        return simpleRetryPolicy;
    }

}

Согласно классу NeverRetryPolicy, он должен делать это:

RetryPolicy, которая разрешает первую попытку, но никогда не разрешает повторную попытку. Также можно использовать в качестве базового класса для других политик, например. в тестовых целях как заглушка.

Насколько я понимаю, первая попытка — это когда мы достигаем конечной точки, мы получаем статус ошибки http 400, а затем никогда не повторяем попытку.

Что случилось с этим?


person Columb1a    schedule 23.05.2017    source источник
comment
Откуда вы звоните handleHttpErrorCode? И что вы делаете с результатом? Выглядит странно выбирать политику во время выполнения, но я могу упустить более широкую картину. Отредактируйте вопрос, чтобы добавить код вызова и настройку шаблона повторной попытки.   -  person Gary Russell    schedule 23.05.2017
comment
Вопрос @GaryRussell обновлен.   -  person Columb1a    schedule 23.05.2017


Ответы (1)


Вы всегда возвращаете политику по умолчанию; похоже, вам нужен return здесь...

return handleHttpErrorCode(statusCode);

Кстати, было бы лучше создавать политики один раз, а не создавать каждый раз новую.

person Gary Russell    schedule 23.05.2017
comment
Ты прав! , Также код не должен возвращать defaultRetry в конце. Вместо этого вместо этого он должен возвращать neverRetry(), и с этим я могу гарантировать, что не буду повторять попытку, если я получу что-то отличное от HttpStatusCodeException - person Columb1a; 23.05.2017