【发布时间】:2020-06-22 00:14:14
【问题描述】:
我正在使用 Spring Boot 2.1.14.RELEASE、Java8、Spring Boot。 我有一个客户,我必须从中访问另一个休息服务。 我需要重试 Http404 和 HTTP500 2 次,而不重试任何其他异常。
我正在使用 RestTemplate 来调用 rest 服务,如下所示:
restTemplate.postForEntity(restUrl, requestEntity, String.class);
我研究了使用 Retryable 和 RetryTemplate 并使用 RetryTemplate 实现了重试功能。
我通过两种方式实现了这一点:
选项1:
RetryTemplate bean 是:
@Bean
public RetryTemplate retryTemplate() {
RetryTemplate retryTemplate = new RetryTemplate();
FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
fixedBackOffPolicy.setBackOffPeriod(retryProperties.getDelayForCall());
retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
retryTemplate.setRetryPolicy(exceptionClassifierRetryPolicy);
return retryTemplate;
}
ClassifierRetryPolicy 是:
@Component
public class ExceptionClassifierRetryPolicy1 extends ExceptionClassifierRetryPolicy {
@Inject
private RetryProperties retryProperties;
public ExceptionClassifierRetryPolicy1(){
final SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy();
simpleRetryPolicy.setMaxAttempts(2);
this.setExceptionClassifier(new Classifier<Throwable, RetryPolicy>() {
@Override
public RetryPolicy classify(Throwable classifiable) {
if (classifiable instanceof HttpServerErrorException) {
// For specifically 500
if (((HttpServerErrorException) classifiable).getStatusCode() == HttpStatus.INTERNAL_SERVER_ERROR) {
return simpleRetryPolicy;
}
return new NeverRetryPolicy();
}
else if (classifiable instanceof HttpClientErrorException) {
// For specifically 404
if (((HttpClientErrorException) classifiable).getStatusCode() == HttpStatus.NOT_FOUND) {
return simpleRetryPolicy;
}
return new NeverRetryPolicy();
}
return new NeverRetryPolicy();
}
});
}
}
在我的客户端类中,我正在使用这样的 retryTemplate:
public void postToRestService(...,...){
...
retryTemplate.execute(context -> {
logger.info("Processing request...");
responseEntity[0] = restTemplate.postForEntity(restURL, requestEntity, String.class);
return null;
}, context -> recoveryCallback(context));
...
}
正在调用的其余服务在每个请求上都抛出 HTTP404。
我的期望是:客户端应该提交一个请求,接收到 HTTP404,并执行 2 次重试。所以在调用recovery回调方法之前,总共有3个请求提交到rest服务。
我的观察是:客户端正在提交 2 个休息服务请求。
根据我阅读的有关 RetryTemplate 的内容,上述观察是有意义的。
所以问题是:
-
上述retryTemplate的实现是否正确?如果没有,如何实现和调用它?我尝试实现的另一个选项(但没有取得任何进展)是在客户端方法上使用 RetryListenerSupport 并在 onError 方法中调用 retryTemplate。
-
我们是否应该将重试次数增加 1 以达到预期效果?我已经尝试过了,它得到了我需要的东西,但创建 RetryTemplate 时并没有考虑到这个目的。
OPTION2:上面#1中提到的代码实现选项:
客户端方法:
@Retryable(listeners = "RestClientListener")
public void postToRestService(...,...){
...
responseEntity[0] = restTemplate.postForEntity(restURL, requestEntity, String.class);
...
}
听众:
public class RestClientListener extends RetryListenerSupport {
private static final Logger logger = LoggerFactory.getLogger(RestClientListener.class);
@Inject
RestTemplate restTemplate;
@Inject
RetryTemplate retryTemplate;
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
logger.info("Retrying count for RestClientListener "+context.getRetryCount());
...
final ResponseEntity<String>[] responseEntity = new ResponseEntity[]{null};
if( context.getLastThrowable().getCause() != null &&
(context.getLastThrowable().getCause() instanceof RestClientResponseException &&
((RestClientResponseException) context.getLastThrowable().getCause()).getRawStatusCode() == HttpStatus.NOT_FOUND.value()))
{
logger.info("Retrying now: ", context.getLastThrowable().toString());
retryTemplate.execute(context2 -> {
logger.info("Processing request...: {}", context2);
responseEntity[0] = restTemplate.postForEntity(restURL, requestEntity, String.class);
return responseEntity;
}, context2 -> recoveryCallback(context2));
}
else {
// Only retry for the above if condition
context.setExhaustedOnly();
}
}
}
这种方法的问题是我找不到在客户端和 clientListener 类之间共享对象的方法。这些对象是创建 requestEntity 和 header 对象所必需的。如何实现?
【问题讨论】:
标签: spring spring-boot java-8 spring-retry retrytemplate