弹性4j 重试和"java.net.http.HttpClient"协同工作时遇到的问题



我正在尝试获得一个基本的"httpclient"httprequest"httpresponse";使用Resilience4j Retry。

逐字逐句的代码来自:https://resilience4j.readme.io/docs/retry

RetryConfig config = RetryConfig.custom()
.maxAttempts(5)
.waitDuration(Duration.ofMillis(1000))
.retryOnResult(response -> response.getStatus() == 500)
.retryOnException(e -> e instanceof WebServiceException)
.retryExceptions(IOException.class, TimeoutException.class)
.ignoreExceptions(BusinessException.class, OtherBusinessException.class)
.build();
// Create a RetryRegistry with a custom global configuration
RetryRegistry registry = RetryRegistry.of(config);
// Get or create a Retry from the registry - 
// Retry will be backed by the default config
Retry retryWithDefaultConfig = registry.retry("name1");

注意,他们上面的代码没有定义通用的";T";,像这样:

RetryConfig config = RetryConfig.<MyConcrete>custom()

以及来自以下内容的逐字编码:https://resilience4j.readme.io/docs/examples

Supplier<String> supplierWithResultAndExceptionHandler = SupplierUtils
.andThen(supplier, (result, exception) -> "Hello Recovery");
Supplier<HttpResponse> supplier = () -> httpClient.doRemoteCall();
Supplier<HttpResponse> supplierWithResultHandling = SupplierUtils.andThen(supplier, result -> {
if (result.getStatusCode() == 400) {
throw new ClientException();
} else if (result.getStatusCode() == 500) {
throw new ServerException();
}
return result;
});
HttpResponse httpResponse = circuitBreaker
.executeSupplier(supplierWithResultHandling);

======

因此使用这2〃;部分",我想出了这个。

注意,我正在使用一些";真实的";java.net.HttpClient和java.net.HttpResponse(来自JDK11(

import io.github.resilience4j.core.SupplierUtils;
import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.retry.RetryConfig;
import io.github.resilience4j.retry.RetryRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import javax.inject.Inject;
import java.io.IOException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.concurrent.TimeoutException;
import java.util.function.Supplier;
public final class ResilientHttpClient /* implements IResilientHttpClient */ {
private static Logger logger;
private final HttpClient httpClient;
@Inject
public ResilientHttpClient(final HttpClient httpClient) {
this(LoggerFactory
.getLogger(ResilientHttpClient.class), httpClient);
}
/**
* Constructor, which pre-populates the provider with one resource instance.
*/
public ResilientHttpClient(final Logger lgr,
final HttpClient httpClient) {
if (null == lgr) {
throw new IllegalArgumentException("Logger is null");
}
this.logger = lgr;
if (null == httpClient) {
throw new IllegalArgumentException("HttpClient is null");
}
this.httpClient = httpClient;
}
public String executeHttpRequest(String circuitbreakerInstanceName, HttpRequest httpRequest) {
try {
/* circuitbreakerInstanceName  is future place holder for .yml configuration see : https://resilience4j.readme.io/docs/getting-started-3 */
RetryConfig config = RetryConfig.<HttpResponse>custom()
.waitDuration(Duration.ofMillis(1000))
.retryOnResult(response -> response.statusCode() == 500)
.retryOnException(e -> e instanceof ArithmeticException)
.retryExceptions(IOException.class, TimeoutException.class)
//.ignoreExceptions(BusinessException.class, OtherBusinessException.class)
.build();
// Create a RetryRegistry with a custom global configuration
RetryRegistry registry = RetryRegistry.of(config);
// Get or create a Retry from the registry -
// Retry will be backed by the default config
Retry retryWithDefaultConfig = registry.retry(circuitbreakerInstanceName);
Supplier<HttpResponse> supplier = () -> this.httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
Supplier<String> supplierWithResultAndExceptionHandler = SupplierUtils
.andThen(supplier, (result, exception) -> "Hello Recovery");
Supplier<HttpResponse> supplierWithResultHandling = SupplierUtils.andThen(supplier, result -> {
if (result.statusCode() == HttpStatus.BAD_REQUEST.value()) {
throw new RuntimeException("400");
} else if (result.statusCode() == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
throw new RuntimeException("500");
}
return result;
});
HttpResponse<String> response = retryWithDefaultConfig.executeSupplier(supplierWithResultHandling);
String responseBody = response.body();
return responseBody;
} catch (Exception ex) {
throw new RuntimeException((ex));
}
}
}

我遇到的问题是:

线路:

Supplier<HttpResponse> supplier = () - > this.httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());

给出了(intelliJ中的("0"的错误;未处理的异常"IOException、InterruptedException";

因此修改方法为:

public String executeHttpRequest(String circuitbreakerInstanceName, HttpRequest httpRequest) throws IOException, InterruptedException {

"感觉不对";。但即使我尝试了……也解决不了任何问题(

这可能是某种蹩脚的异常伏都教。

但更重要的是:

所以我不知道我把这两个部分组合在一起的方式是否正确。样品在完全工作的区域有点少。

谢谢你的帮助。获得一个基本的httpclient"重试";几次应该不会太难。但我的头撞到墙上了。

我的等级依赖。

dependencies {
implementation group: 'javax.inject', name: 'javax.inject', version: javaxInjectVersion
implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion
implementation group: 'org.springframework', name: 'spring-web', version: springWebVersion
implementation "io.github.resilience4j:resilience4j-circuitbreaker:${resilience4jVersion}"
implementation "io.github.resilience4j:resilience4j-ratelimiter:${resilience4jVersion}"
implementation "io.github.resilience4j:resilience4j-retry:${resilience4jVersion}"
implementation "io.github.resilience4j:resilience4j-bulkhead:${resilience4jVersion}"
implementation "io.github.resilience4j:resilience4j-cache:${resilience4jVersion}"
implementation "io.github.resilience4j:resilience4j-timelimiter:${resilience4jVersion}"

testCompile group: 'junit', name: 'junit', version: junitVersion
}

resilience4jVersion = '1.5.0'
slf4jVersion = "1.7.30"
javaxInjectVersion = "1"
springWebVersion = '5.2.8.RELEASE'
junitVersion = "4.12"

只是出于兴趣:

  • 您正在使用哪个Java版本?Java 11
  • 为什么不能使用Spring Boot?Resilience4j Spring Boot启动器大大简化了配置

如果配置retryOnResult(response -> response.getStatus() == 500),就不必再使用SupplierUtils将具有特定状态代码的HttpResponse映射到运行时异常。

RetryConfig config = RetryConfig.<HttpResponse<String>>custom()
.waitDuration(Duration.ofMillis(1000))
.retryOnResult(response -> response.statusCode() == 500)
.retryExceptions(IOException.class, TimeoutException.class)
.build();

请不要在executeHttpRequest内部创建注册表和配置,而是将它们注入构造函数。

您可以创建这样的静态方法:

public static <T> HttpResponse<T> executeHttpRequest(Callable<HttpResponse<T>> callable, Retry retry, CircuitBreaker circuitBreaker) throws Exception {
return Decorators.ofCallable(callable)
.withRetry(retry)
.withCircuitBreaker(circuitBreaker)
.call();
}

并调用如下方法:

HttpResponse<String> response = executeHttpRequest(
() -> httpClient.send(request, HttpResponse.BodyHandlers.ofString()), 
retry, 
circuitBreaker);

最新更新