我需要对可能失败的请求实现指数回退。但是,它是作为异步请求实现的。如果这是同步完成的,我会更好地了解延迟的位置。大致上,我认为它会像这样工作:
// These would be configurable in application.yml
currentAttempt = 0;
maxAttempts = 3;
timeoutGrowth = 2;
currentDelayTime = 5ms;
repeatNeeded = false;
while(repeatNeeded && currentAttempt < maxAttempts) {
httpStatusCode = makeRequest(someService)
if(httpStatusCode == 503) {
repeatNeeded=true;
currentAttempt++;
currentDelayTime*=timeoutGrowthRate;
sleep(currentDelayTime)
}
}
然而,通过异步调用,函数的调用方有时间做其他事情,直到Future有了东西。我是在下面的getObservations((方法中编码回退,还是在该getObservation((方法的调用方中编码回退?以下是目前的呼叫:
public CompletableFuture getObservations(字符串文本、映射<字符串、对象>bodyParams(抛出URISyntaxException{URI URI=getUri(文本(;HttpRequest请求=getRequest(uri,text,bodyParams(;映射<字符串,字符串>contextMap=可选.Nullable(MDC.getCopyOfContextMap(((或Else(Collections.emptyMap((;
Instant startTime = Instant.now();
return httpClient.sendAsync(request, BodyHandlers.ofString())
.exceptionally(ex -> {
throw new ExternalToolException(externalServiceConfig.getName(), ex);
})
.thenApply(response -> {
long toolRequestDurationMillis = ChronoUnit.MILLIS.between(startTime, Instant.now());
if (HttpStatus.valueOf(response.statusCode()).is2xxSuccessful()) {
ToolResponse toolResponse = processResponse(response, toolRequestDurationMillis);
logToolResponse(toolResponse);
return toolResponse;
}
log.error("{} returned non-200 response code: {}", externalServiceConfig.getName(), response.statusCode());
throw new ExternalToolException(externalServiceConfig.getName(), response.statusCode());
});
}
如果您可以考虑使用具有非常强大的API(包括重试(的响应式java。例如,
request()
.retryWhen(Retry.backoff(3, Duration.ofSeconds(2)));
.maxBackoff(5)
.filter(throwable -> isRetryableError(throwable))
还有更多的选项,比如只为特定的异常重试,或者定义最大回退
webClient.get()
.uri("/api")
.retrieve()
.bodyToMono(String.class)
.retryWhen(Retry.backoff(3, Duration.ofSeconds(1)));
您可以使用CompletableFuture
,它是一个非阻塞客户端,通过底层的HTTP客户端库(如Reactor Netty (公开流畅、反应式的API
Mono.fromFuture(httpClient.sendAsync(request, BodyHandlers.ofString()))
.retryWhen(Retry.backoff(3, Duration.ofSeconds(1)));
如果出于某种原因,您仍然希望使用HttpClient,则可以包装CCD_3
PD_7