8

@RetryableREST テンプレートを呼び出すメソッドで使用しようとしています。通信エラーが原因でエラーが返された場合は、再試行したいのですが、それ以外の場合は、呼び出しで例外をスローしたいだけです。

ApiException が発生すると、@Retryable によってスローされて無視されるのではなく、十分な「回復可能」、つまりメソッドExhaustedRetryExceptionが見つからないという苦情が発生します。@Recover

回復可能なメソッドが存在するだけで満足し、期待どおりに機能するかどうかを確認したいと思いました。それほどでもない。例外をスローする代わりに、回復可能なメソッドを呼び出しました。

@Retryable(exclude = ApiException include = ConnectionException, maxAttempts = 5, backoff = @Backoff(multiplier = 2.5d, maxDelay = 1000000L, delay = 150000L))
Object call(String domainUri, ParameterizedTypeReference type, Optional<?> domain = Optional.empty(), HttpMethod httpMethod = HttpMethod.POST) throws RestClientException {

    RequestEntity request = apiRequestFactory.createRequest(domainUri, domain, httpMethod)
    log.info "************************** Request Entity **************************"
    log.info "${request.toString()}"
    ResponseEntity response

    try {

        response = restTemplate.exchange(request, type)
        log.info "************************** Response Entity **************************"
        log.info "${response.toString()}"

    } catch (HttpStatusCodeException | HttpMessageNotWritableException httpException) {

        String errorMessage
        String exceptionClass = httpException.class.name.concat("-")
        if(httpException instanceof HttpStatusCodeException) {

            log.info "************************** API Error **************************"
            log.error("API responded with errors: ${httpException.responseBodyAsString}")
            ApiError apiError = buildErrorResponse(httpException.responseBodyAsString)
            errorMessage = extractErrorMessage(apiError)

            if(isHttpCommunicationError(httpException.getStatusCode().value())) {
                throw new ConnectionException(exceptionClass.concat(errorMessage))
            }
        }

        errorMessage = StringUtils.isBlank(errorMessage) ? exceptionClass.concat(httpException.message) : exceptionClass.concat(errorMessage)
        throw new ApiException(httpMethod, domainUri, errorMessage)

    }

    if (type.type == ResponseEntity) {
        response
    }
    else response.body

}

@Recover
Object connectionException(ConnectionException connEx) {
    log.error("Retry failure - communicaiton error")
    throw new ConnectionException(connEx.class.name + " - " + connEx.message)
}

任意の洞察をいただければ幸いです。バグですか、それともオペレーターのミスですか?これは Spring Boot 1.3.6 と Spring-Retry 1.1.3 を使用しています。

4

1 に答える 1

7

あなたの include/exclude 構文は悪いように見えます - それはコンパイルさえしません。

簡単なテストを書いたところ、メソッドがゼロの場合、期待どおりに動作します@Recover...

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.annotation.Retryable;

@SpringBootApplication
@EnableRetry
public class So38601998Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(So38601998Application.class, args);
        Foo bean = context.getBean(Foo.class);
        try {
            bean.out("foo");
        }
        catch (Exception e) {
            System.out.println(e);
        }
        try {
            bean.out("bar");
        }
        catch (Exception e) {
            System.out.println(e);
        }
    }


    @Bean
    public Foo foo() {
        return new Foo();
    }

    public static class Foo {

        @Retryable(include = IllegalArgumentException.class, exclude = IllegalStateException.class,
                maxAttempts = 5)
        public void out(String foo) {
            System.out.println(foo);
            if (foo.equals("foo")) {
                throw new IllegalArgumentException();
            }
            else {
                throw new IllegalStateException();
            }
        }

    }

}

結果:

foo
foo
foo
foo
foo
java.lang.IllegalArgumentException
bar
java.lang.IllegalStateException

追加するだけなら

@Recover
public void connectionException(IllegalArgumentException e) {
    System.out.println("Retry failure");
}

あなたが得る

foo
foo
foo
foo
foo
Retry failure
bar
org.springframework.retry.ExhaustedRetryException: Cannot locate recovery method; nested exception is java.lang.IllegalStateException

だから、キャッチオール@Recoverメソッドが必要です...

@Recover
public void connectionException(Exception e) throws Exception {
    System.out.println("Retry failure");
    throw e;
}

結果:

foo
foo
foo
foo
foo
Retry failure
bar
Retry failure
java.lang.IllegalStateException
于 2016-07-27T13:13:07.740 に答える