Apache 5 HttpClient 重试策略不起作用

问题描述 投票:0回答:2

我正在尝试向我的 HttpClient 添加自定义重试策略,以便它在 SocketTimeoutException 和 NoHttpResponseException 上重试。但是,如果出现这些错误,则不会调用自定义重试策略。 请找到下面的代码片段:

创建 HttpClient:

    val requestConfig = RequestConfig.custom()
        .setConnectTimeout(Timeout.ofMilliseconds(20))
        .setResponseTimeout(Timeout.ofMilliseconds(1000))
        .setConnectionRequestTimeout(Timeout.ofMilliseconds(200))
        .build()

    val retryStrategy = CustomRetryStrategy(
        3, // Retry 3 times
        TimeValue.ofMilliseconds(10) // Retry very quickly
    )
    

    val client = HttpClientBuilder.create()
        .setDefaultRequestConfig(requestConfig)
        .setRetryStrategy(retryStrategy)
        .build()

重试策略代码:


class CustomRetryStrategy(private val maxRetries: Int, private val defaultRetryInterval: TimeValue) :
    DefaultHttpRequestRetryStrategy(maxRetries, defaultRetryInterval) {

    override fun retryRequest(request: HttpRequest, exception: IOException, execCount: Int, context: HttpContext?): Boolean {
        if (execCount > this.maxRetries) {
            // Do not retry if over max retries
            return false
        }

        if (exception is SocketTimeoutException ||
            exception.cause is SocketTimeoutException ||
            exception.cause is NoHttpResponseException ||
            exception is NoHttpResponseException
        ) {
            println("Retryable Exception Encountered. Retrying")
            return true
        }
        return super.retryRequest(request, exception, execCount, context)
    }
}

执行请求代码:

val response = client.execute(request)

我可以知道我错过了什么或做错了什么导致重试未执行吗?

java apache-httpcomponents socket-timeout-exception apache-httpclient-5.x
2个回答
1
投票

默认重试策略测试调用是否幂等(可以进行多次调用,其结果与调用 1 时相同),您的调用很可能会失败此测试。我正在使用 5 版本而不是 4,但应该类似。在 5 中,您需要一个实现 HttpRequestRetryStrategy 的自定义 HttpRequestRetryStrategy 类,如果您基于 DefaultHttpRequestRetryStrategy,您可以更新函数 handleAsIdempot 以在您想要重试的情况下返回 true。

可能有更好的方法,但这就是我在找不到发布的解决方案后通过跟踪库代码来解决问题的方法。


0
投票

万一其他人发现自己在此页面中并希望看到一些 Java 代码对所有错误/异常执行自定义重试策略,因为默认错误/异常会排除某些错误/异常。

public static void main(String[] args) throws IOException {
    final ClassicHttpRequest httpGet = ClassicRequestBuilder.get("https://httpbin.org/status/500")
            .build();

    CloseableHttpClient httpClient = HttpClientBuilder
            .create()
            .setRetryStrategy(new CustomRetryStrategy(3, TimeValue.ofSeconds(3)))
            .build();

    httpClient.execute(httpGet, response -> {
        System.out.println(response.getCode() + " " + response.getReasonPhrase());
        return null;
    });
}

static class CustomRetryStrategy implements HttpRequestRetryStrategy {
    private final int maxRetries;
    private final TimeValue retryInterval;

    public CustomRetryStrategy(final int maxRetries, final TimeValue retryInterval) {
        this.maxRetries = maxRetries;
        this.retryInterval = retryInterval;
    }

    @Override
    public boolean retryRequest(
            final HttpRequest request,
            final IOException exception,
            final int execCount,
            final HttpContext context) {
        Args.notNull(request, "request");
        Args.notNull(exception, "exception");

        if (execCount > this.maxRetries) {
            // Do not retry if over max retries
            return false;
        }
        return true;
    }

    @Override
    public boolean retryRequest(
            final HttpResponse response,
            final int execCount,
            final HttpContext context) {
        Args.notNull(response, "response");

        return execCount <= this.maxRetries;
    }

    @Override
    public TimeValue getRetryInterval(HttpResponse response, int execCount, HttpContext context) {
        System.out.println("Retrying HTTP request after " + retryInterval.toString());
        return retryInterval;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.