如何在Apache httpclient中使用指数退避策略?

时间:2016-02-14 11:03:55

标签: java apache httpclient

docs指定了一个ExponentialBackOffSchedulingStrategy类,但它似乎不存在于4.5版本中。

此外,没有找到解释如何使用它的任何内容。

之前有人使用过这样的东西吗?

2 个答案:

答案 0 :(得分:0)

如果你使用像这样的Maven包安装Apache HTTP Client 4.5.x(Grails Maven依赖语法):

compile "org.apache.httpcomponents:httpclient:4.5.1"
compile "org.apache.httpcomponents:httpcore:4.4.3"

你需要添加另一个jar来获取这些类,如下所示:

compile 'org.apache.httpcomponents:httpclient-cache:4.5.1'

请参阅https://hc.apache.org/httpcomponents-client-4.5.x/download.html

然后你可以把它连接起来:

 import org.apache.http.impl.client.*;
 import org.apache.http.impl.client.cache.*;
 import org.apache.http.client.methods.*;

 CloseableHttpClient createClient() {
     CachingHttpClientBuilder hcb = new CachingHttpClientBuilder();
     CacheConfig cc = CacheConfig.DEFAULT;
     ExponentialBackOffSchedulingStrategy ebo = new ExponentialBackOffSchedulingStrategy(cc);
     hcb.setSchedulingStrategy(ebo);
     CloseableHttpClient hc = hcb.build();
     return hc;
 }

 // You'll need to replace the URL below with something that returns a 5xx error
 CloseableHttpClient client = createClient();
 HttpUriRequest request = new HttpGet("http://www.example.com/throwsServerError");
 for (int i=0; i<4; i++) {
     CloseableHttpResponse response =  client.execute(request);
     println new Date().toString() + " " + response.getStatusLine().getStatusCode();
 }

答案 1 :(得分:0)

ExponentialBackOffSchedulingStrategy适用于缓存的条目,这就是为什么它只能与CachingClient一起使用的原因。我认为它不能用于对失败的请求实施指数补偿重试机制。

我将按照以下方式实施简单的指数补偿策略:

class MyExponentialBackoffRetryHandler extends HttpRequestRetryHandler {
  public MyExponentialBackoffRetryHandler(int maxNumRetries, int backOffRate, int initialExpiry, int maxExpiry) {
  } 
 boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
   if (executionCount == maxNumRetries) {
     return false;
   }else {
     long nextBackOffDelay = initialExpiry * Math.pow(backOffRate, executionCount - 
1)
     long delay = Math.min(maxExpiry, nextBackOffDelay)
     Thread.sleep(delay);
     return true;
   } 

}
}

此外,为了触发重试,您需要添加一个引发IOException的响应拦截器,例如:

class MyResponseInterceptor extends HttpResponseInterceptor {
  void process(HttpResponse response, HttpContext context) throws HttpException, IOException {
    if (response.getStatusLine.getStatusCode == 503) {
        throw new IOException("Please retry")
    }
  }
}

最后,您可以构建HTTP客户端实例,如下所示:

HttpClientBuilder
    .create()
    .setRetryHandler(new MyExponentialBackoffRetryHandler(...))
    .addInterceptorFirst(new MyResponseInterceptor())
    .build()

您可以通过向https://httpstat.us/503发送请求轻松地测试客户端