请求重试 Apache HttpClient 之间的超时



>有人可以分享如何配置现代 HttpClient 4.5.3 以重试失败的请求并在每次重试之前等待一段时间吗?

到目前为止,看起来我做对了,.setRetryHandler(new DefaultHttpRequestRetryHandler(X, false))将允许重试请求 X 次。

但是我不明白如何配置退避:根据JavaDocs .setConnectionBackoffStrategy()/.setBackoffManager()调节其他内容,而不是重试之间的超时。

关于动态延迟,我想提出这样的建议:

CloseableHttpClient client = HttpClientBuilder.create()
    .setRetryHandler(new HttpRequestRetryHandler() {
        @Override
        public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
            return executionCount <= maxRetries ;
        }
    })
    .setServiceUnavailableRetryStrategy(new ServiceUnavailableRetryStrategy() {
        int waitPeriod = 100;
        @Override
        public boolean retryRequest(HttpResponse response, int executionCount, HttpContext context) {
            waitPeriod *= 2;
            return executionCount <= maxRetries &&
               response.getStatusLine().getStatusCode() >= 500; //important!
        }
        @Override
        public long getRetryInterval() {
            return waitPeriod;
        }
    })
    .build();

附录:请注意,如果出现超时、端口未打开或连接关闭等 IO 错误,则不会调用 ServiceUnavailableRetryStrategy.retryRequest。在这种情况下,只会调用 HttpRequestRetryHandler.retryRequest,并且重试将立即或在固定延迟后发生(我无法最终澄清这一点(。所以奥列格的答案其实是正确的。在支持HttpClient 4.5的情况下无法做到这一点。

(我实际上想称之为设计错误,因为 IO 错误后的延迟重试在现代微服务环境中至关重要。

BackoffManager/

ConnectionBackoffStrategy 组合可用于根据 I/O 错误率和 503 响应动态增加或减少每个路由的最大连接数限制。它们对请求执行没有影响,不能用于控制请求的重新执行

这是使用 HC 4.x API 可以做到的最好的事情

CloseableHttpClient client = HttpClientBuilder.create()
        .setRetryHandler(new HttpRequestRetryHandler() {
            @Override
            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                return executionCount <= maxRetries &&
                        exception instanceof SocketException;
            }
        })
        .setServiceUnavailableRetryStrategy(new ServiceUnavailableRetryStrategy() {
            @Override
            public boolean retryRequest(HttpResponse response, int executionCount, HttpContext context) {
                return executionCount <= maxRetries &&
                        response.getStatusLine().getStatusCode() == HttpStatus.SC_SERVICE_UNAVAILABLE;
            }
            @Override
            public long getRetryInterval() {
                return 100;
            }
        })
        .build();

请注意,目前没有优雅的方法可以在发生 I/O 错误时强制请求执行尝试之间的延迟,或者根据请求路由动态调整重试间隔。

你可以

使用 lambda

client.setRetryHandler((e, execCount, httpContext) -> {
                if (execCount > tries) {
                    return false;
                } else {
                    try {
                        Thread.sleep(recalMillis);
                    } catch (InterruptedException ex) {
                        //ignore
                    }
                    return true;
                }

请注意,处理程序仅适用于 IOExceptions 类型

这对

我们有用。这会重试 (3( 和延迟 (1000ms(。我们覆盖两件事,HttpResponseInterceptor.process()HttpRequestRetryHandler.retryRequest()。第一个将针对无效 (400+( HTTP 代码抛出异常,这些代码将出现在retryRequest实现中。注意:如果所有重试都已用尽,您将在此代码段底部找到最终的 Catch。

// Define an HttpClient with the following features:
// 1) Intercept HTTP response to detect any 400+ HTTP Codes (process() implementation), and if so,
// 2) Force a retry with a delay (HttpRequestRetryHandler.retryRequest() implementation)
final CloseableHttpClient httpClient = HttpClients.custom().addInterceptorLast(new HttpResponseInterceptor() {
    @Override
    public void process(HttpResponse response, HttpContext context) throws HttpException, IOException {
        if (response.getStatusLine().getStatusCode() >= 400) {
            // Throw an IOException to force a retry via HttpRequestRetryHandler.retryRequest()
            throw new IOException("Invalid code returned: " + response.getStatusLine().getStatusCode());
        }       
    }
})
.setRetryHandler(new HttpRequestRetryHandler() {
    @Override
    public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
        if (executionCount > MAX_RETRIES) { // MAX_RETRIES = 3
            return false;
        } else {
            try {
                // Sleep before retrying
                Thread.sleep(DELAY); // DELAY = 1000 MS
            } catch (InterruptedException ex) {
                // ... Log or silently swallow 
            }
            return true;
        }       
    }
})
.build();
final HttpGet getOp = new HttpGet("http://yoururl.com/api/123/");
try {
    return httpClient.execute(getOp, new ResponseHandler<String>() {
        @Override
        public String handleResponse(final HttpResponse response) throws ClientProtocolException, IOException {
            // ... Process response after preliminary HTTP code verification
        }
    });
} catch (IOException ioe) {
    // NOTE: Comes here if all retries have failed, throw error back to caller
    log.error("All retries have been exhausted");
    throw ioe;
}

最新更新