本文介绍了尝试使用@Retryable排除异常 - 会导致引发ExhaustedRetryException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在调用REST模板的方法上使用 @Retryable 。如果由于通信错误而返回错误,我想重试,否则我只想在调用中抛出一个异常。



当ApiException发生时,而不是它被@Retryable抛出和忽略,我得到一个 ExhaustedRetryException 和一个关于没有找到足够的'recoverables'的投诉,即 @Recover

我想我会看到如果只有可恢复的方法可能会使它感到快乐,并仍然按照希望执行。没那么多。

  @Retryable(exclude = ApiException include = ConnectionException,maxAttempts = 5, backoff = @Backoff(multiplier = 2.5d,maxDelay = 1000000L,delay = 150000L))
对象调用(String domainUri,ParameterizedTypeReference type,可选<?> domain = Optional.empty(),HttpMethod httpMethod = HttpMethod。 POST)抛出RestClientException {

RequestEntity request = apiRequestFactory.createRequest(domainUri,domain,httpMethod)
log.info**************** **********请求实体**************************
log.info$ {request .toString()}
ResponseEntity响应

尝试{

响应= restTemplate.exchange(请求,类型)
log.info** ************************回应实体************************ **
log.info$ {response.toString()}

} catch(HttpStatusCodeException | HttpMessageNotWri如果(httpException instanceof HttpStatusCodeException){
$ b() $ b log.info************************** API错误**************** **********
log.error(API响应错误:$ {httpException.responseBodyAsString})
ApiError apiError = buildErrorResponse(httpException.responseBodyAsString)
errorMessage = extractErrorMessage(apiError)

if(isHttpCommunicationError(httpException.getStatusCode()。value())){
抛出ConnectionException(exceptionClass.concat(errorMessage))
}
}

errorMessage = StringUtils.isBlank(errorMessage)? exceptionClass.concat(httpException.message):exceptionClass.concat(errorMessage)
抛出新的ApiException(httpMethod,domainUri,errorMessage)

}

if(type。键入== ResponseEntity){
响应
}
else response.body


$ b @Recover
Object connectionException( ConnectionException connEx){
log.error(Retry failure - communicaiton error)
抛出新的ConnectionException(connEx.class.name + - + connEx.message)
}

任何见解都将不胜感激。这是一个错误还是操作员错误?
这是使用Spring Boot 1.3.6和Spring-Retry 1.1.3。

解决方案
你的包含/看起来很糟糕 - 甚至不会编译。



我刚写了一个快速测试,它的工作原理与预期完全一致,如果您的零 @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);
尝试{
bean.out(foo);
}
catch(Exception e){
System.out.println(e);
}
尝试{
bean.out(bar);
}
catch(Exception e){
System.out.println(e);



$ b @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(重试失败);
}

您得到

  foo 
foo
foo
foo
foo
重试失败
bar
org.springframework。 retry.ExhaustedRetryException:找不到恢复方法;嵌套异常是java.lang.IllegalStateException

所以你需要一个全面的 @Recover 方法...

  @Recover 
public void connectionException(Exception e)抛出异常{
System.out.println(重试失败);
throw e;

结果:

  foo 
foo
foo
foo
foo
重试失败
bar
重试失败
java.lang.IllegalStateException


I'm trying to use @Retryable on a method that calls the REST template. If an error is returned due to a communication error, I want to retry otherwise I want to just thrown an exception on the call.

When the ApiException occurs, instead of it being thrown and ignored by @Retryable, I get an ExhaustedRetryException and a complaint about not finding enough 'recoverables', i.e, @Recover methods.

I thought I'd see if just having the recoverable method present might make it happy and still perform as hoped for. Not so much. Instead of throwing the exception, it called the recoverable method.

@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)
}

Any insights would be appreciated. Is it a bug or operator error?This is using Spring Boot 1.3.6 and Spring-Retry 1.1.3.

解决方案

Your include/exclude syntax looks bad - that won't even compile.

I just wrote a quick test and it works exactly as expected if you have zero @Recover methods...

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();
            }
        }

    }

}

Result:

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

If you just add

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

You get

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

So you need a catch-all @Recover method...

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

Result:

foo
foo
foo
foo
foo
Retry failure
bar
Retry failure
java.lang.IllegalStateException

这篇关于尝试使用@Retryable排除异常 - 会导致引发ExhaustedRetryException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-10 15:36