HttpClient-RetryHandler重試(一)

目前的項目接口都是http,因此在java項目中使用apache httpclient進行數(shù)據(jù)傳輸、訪問。

目前程序中涉及到需要callback操作,product需要被動的接收consume的處理狀態(tài),為了最大程度的能夠callback成功因此consume在http調(diào)用出現(xiàn)問題(如:服務(wù)不可用、異常、超時)情況下需要進行重試(retry request),在這里我列舉出我找到的retry方案,有些成功有些不成功。

我是用的httpclient版本是4.5.2。關(guān)于retry功能我在網(wǎng)上也找了不少的資料,但是都不是我對應(yīng)的httpclient版本,大多是過時的。

在httpclient版本4.5.2提供了以下幾種retry方案:

StandardHttpRequestRetryHandler

這種方案沒有測試通過,StandardHttpRequestRetryHandler實際上是DefaultHttpRequestRetryHandler的子類,這是官方提供的一個標(biāo)準(zhǔn)的retry方案,為了保證冪等性約定resetful接口必須是GET, HEAD, PUT, DELETE, OPTIONS, and TRACE中的一種,如下,是我定義的httpclient pool,

public static CloseableHttpClient getHttpClient() {
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(MAX_TOTAL);
        cm.setDefaultMaxPerRoute(MAX_PERROUTE);
        CloseableHttpClient httpClient = HttpClients
                .custom()
                .setRetryHandler(new StandardHttpRequestRetryHandler())
                .setConnectionManager(cm)
                .build();
        return httpClient;
    }1234567891011

如下是我的測試代碼,

@Test
    public void test6(){
        HttpPost httpPost=new HttpPost("http://127.0.0.1:8080/testjobs1");
        try {
            rsp=httpClient.execute(httpPost);
            log.info(">> {}",rsp.getStatusLine().getStatusCode());
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }finally{
            HttpUtil.close(rsp);
        }
    }123456789101112

運行測試,當(dāng)url錯誤、后臺報錯、后臺超時等情況的時候不能進行retry,因此放棄了此方案。

DefaultHttpRequestRetryHandler

這種方案沒有測試通過,和上面的StandardHttpRequestRetryHandler類似,它提供了一種默認的retry方案,并沒有像StandardHttpRequestRetryHandler一樣約定接口必須是冥等的,如下,是我定義的httpclient pool,

public static CloseableHttpClient getHttpClient() {
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(MAX_TOTAL);
        cm.setDefaultMaxPerRoute(MAX_PERROUTE);
        CloseableHttpClient httpClient = HttpClients
                .custom()
                .setRetryHandler(new DefaultHttpRequestRetryHandler())
                .setConnectionManager(cm)
                .build();
        return httpClient;
    }1234567891011

如下是我的測試代碼,

@Test
    public void test6(){
        HttpPost httpPost=new HttpPost("http://127.0.0.1:8080/testjobs1");
        try {
            rsp=httpClient.execute(httpPost);
            log.info(">> {}",rsp.getStatusLine().getStatusCode());
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }finally{
            HttpUtil.close(rsp);
        }
    }123456789101112

依然沒有達到希望的效果。

HttpRequestRetryHandler

可以實現(xiàn),但是不夠完美。在官方文檔有這么一段,如下,

HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {

    public boolean retryRequest(
            IOException exception,
            int executionCount,
            HttpContext context) {
        if (executionCount >= 5) {
            // Do not retry if over max retry count
            return false;
        }
        if (exception instanceof InterruptedIOException) {
            // Timeout
            return false;
        }
        if (exception instanceof UnknownHostException) {
            // Unknown host
            return false;
        }
        if (exception instanceof ConnectTimeoutException) {
            // Connection refused
            return false;
        }
        if (exception instanceof SSLException) {
            // SSL handshake exception
            return false;
        }
        HttpClientContext clientContext = HttpClientContext.adapt(context);
        HttpRequest request = clientContext.getRequest();
        boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
        if (idempotent) {
            // Retry if the request is considered idempotent
            return true;
        }
        return false;
    }

};
CloseableHttpClient httpclient = HttpClients.custom()
        .setRetryHandler(myRetryHandler)
        .build();12345678910111213141516171819202122232425262728293031323334353637383940

自定義retry實現(xiàn),這比較靈活,可以根據(jù)異常自定義retry機制以及重試次數(shù),并且可以拿到返回信息,如下,是我定義的httpclient pool,

public static CloseableHttpClient getHttpClient() {
        HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {
            public boolean retryRequest(
                    IOException exception,
                    int executionCount,
                    HttpContext context) {
                if (executionCount >= 5) {
                    // Do not retry if over max retry count
                    return false;
                }
                if (exception instanceof InterruptedIOException) {
                    // Timeout
                    return false;
                }
                if (exception instanceof UnknownHostException) {
                    // Unknown host
                    return false;
                }
                if (exception instanceof ConnectTimeoutException) {
                    // Connection refused
                    return false;
                }
                if (exception instanceof SSLException) {
                    // SSL handshake exception
                    return false;
                }
                HttpClientContext clientContext = HttpClientContext.adapt(context);
                HttpRequest request = clientContext.getRequest();
                boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
                if (idempotent) {
                    // Retry if the request is considered idempotent
                    return true;
                }
                return false;
            }
        };
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(MAX_TOTAL);
        cm.setDefaultMaxPerRoute(MAX_PERROUTE);
        CloseableHttpClient httpClient = HttpClients
                .custom()
                .setRetryHandler(retryHandler)
                .setConnectionManager(cm)
                .build();
        return httpClient;
    }12345678910111213141516171819202122232425262728293031323334353637383940414243444546

如下是我的測試代碼,

@Test
    public void test6(){
        HttpPost httpPost=new HttpPost("http://127.0.0.1:8080/testjobs1");
        try {
            rsp=httpClient.execute(httpPost);
            log.info(">> {}",rsp.getStatusLine().getStatusCode());
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }finally{
            HttpUtil.close(rsp);
        }
    }123456789101112

這種方案,可以實現(xiàn)retry,并且可以根據(jù)我的需求進行retry,如:retry count,但是就不能控制retry時間的間隔,也只好放棄了,繼續(xù)尋找找到了下面這個ServiceUnavailableRetryStrategy

ServiceUnavailableRetryStrategy

可以實現(xiàn),滿足需求,這具有HttpRequestRetryHandler的所有有點,并且可以自定義retry時間的間隔,如下,是我定義的httpclient pool,

public static CloseableHttpClient getHttpClient() {
        ServiceUnavailableRetryStrategy serviceUnavailableRetryStrategy = new ServiceUnavailableRetryStrategy() {
            /**
             * retry邏輯
             */
            @Override
            public boolean retryRequest(HttpResponse response, int executionCount, HttpContext context) {
                if (executionCount <= 3)
                    return true;
                else
                    return false;
            }

            /**
             * retry間隔時間
             */
            @Override
            public long getRetryInterval() {
                return 2000;
            }
        };
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(MAX_TOTAL);
        cm.setDefaultMaxPerRoute(MAX_PERROUTE);
        CloseableHttpClient httpClient = HttpClients.custom().setRetryHandler(new DefaultHttpRequestRetryHandler())
                .setConnectionManager(cm).build();
        return httpClient;
    }12345678910111213141516171819202122232425262728

如下是我的測試代碼,

@Test
    public void test6(){
        HttpPost httpPost=new HttpPost("http://127.0.0.1:8080/testjobs1");
        try {
            rsp=httpClient.execute(httpPost);
            log.info(">> {}",rsp.getStatusLine().getStatusCode());
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }finally{
            HttpUtil.close(rsp);
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容