學習使用Guava Retryer


目錄

  一、引入

  二、快速上手

    2.1、導入依賴

    2.2、第一個示例

  三、重試設置

    3.1、重試條件設置

    3.2、重試次數設置

    3.3、重試間隔設置

 

 

 

一、引入

  在平時的開發工作中,重試機制,是一個很重要的邏輯,比如調用其他服務時,如果出現超時,那么可以等100毫秒后再進行調用,或者出現異常時,需要重試;可以重試多次,也可以重試1次,這個都是可以在程序中設定的。

  實現上面的邏輯,最簡單的方式就是使用for循環了,示例如下:

package cn.ganlixin.guava;

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UseRetryer {

    private static final Logger log = LoggerFactory.getLogger(UseRetryer.class);

    @Test
    public void testUseFor() throws InterruptedException {
        int retryTimes = 3;  // 重試次數

        // 使用for循環控制重試
        for (int i = 0; i < retryTimes; i++) {

            try {
                // 邏輯代碼,比如調用其他服務的接口

            } catch (Exception e) {
                log.warn("第{}次運行出現異常,", i);
                // 如果出現異常,休眠100毫秒后重試(繼續for循環)
                Thread.sleep(100);
                continue;
            }

            // 執行成功,立即終止for循環。
            break;
        }

    }
}

  上面的代碼,實現起來很簡單,也很好理解,我之前也是這樣做的。但是這樣做,其實是有一個弊端的,因為業務邏輯代碼,和一些控制操作(什么時候重試、隔多久重試)是寫在一塊的,比較亂。

  本文所講的Guava Retryer可以解決上面的問題(還有其他優點)。  

 

二、快速上手

2.1、導入依賴

  Guava Retryer並不屬於Guava,他是一個基於Guava,提供重試機制的庫。

  guava retryer的github網址:https://github.com/rholder/guava-retrying,包含有使用文檔。

<dependency>
	<groupId>com.google.guava</groupId>
	<artifactId>guava</artifactId>
	<version>28.0-jre</version>
</dependency>

<dependency>
	<groupId>com.github.rholder</groupId>
	<artifactId>guava-retrying</artifactId>
	<version>2.0.0</version>
	<!-- 排除與guava重復的依賴 -->
	<exclusions>
		<exclusion>
			<groupId>com.google.guava</groupId>
			<artifactId>guava</artifactId>
		</exclusion>
		<exclusion>
			<groupId>com.google.code.findbugs</groupId>
			<artifactId>jsr305</artifactId>
		</exclusion>
	</exclusions>
</dependency>

  

2.2、第一個示例

  先提及一下, retryer是一個重試器,可以對重試器進行設置,比如什么情況下重試、隔多久重試、重試多少次...

  創建好重試器后,就可以使用重試器來進行執行指定的操作(實際的業務邏輯):

package cn.ganlixin.guava;

import com.github.rholder.retry.*;
import org.junit.Test;

import java.time.LocalTime;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class UseRetryer {

    // 需要重試執行的操作
    private Boolean testCode() {
        System.out.println(LocalTime.now());

        // 強制拋出異常,觸發重試
        if (true) {
            throw new RuntimeException("手動測試拋出異常");
        } else {
            return false;
        }
    }

    @Test
    public void testFirstRetryer() throws ExecutionException, RetryException, InterruptedException {
        // 創建一個重試器,重試器執行的方法,返回值為Boolean類型
        Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
                // 出現異常時,會重試
                .retryIfException()
                // 失敗后,隔2秒后重試
                .withWaitStrategy(WaitStrategies.fixedWait(2, TimeUnit.SECONDS))
                // 重試3次后,仍未成功,就不再重試
                .withStopStrategy(StopStrategies.stopAfterAttempt(3))
                .build();

        // 使用重試器,執行具體邏輯
        Boolean res = retryer.call(() -> {
            return testCode();
        });
    }
}

  

  運行程序,輸出:

23:35:37.753
23:35:39.754
23:35:41.759

com.github.rholder.retry.RetryException: Retrying failed to complete successfully after 3 attempts.
..........
Caused by: java.lang.RuntimeException: 手動測試拋出異常
..........

  

三、重試設置

  上面簡單介紹了怎么使用guava retryer,但是並沒有看出retryer的優點,下面對guava retryer的重試設置進行介紹,比如,什么時候重試,重試多少次,每次充重試間隔多久..然后就可以發現guava retryer在進行重試時,挺“優雅”的。

3.1、重試條件設置

  什么時候執行重試,Guava Retryer有多個匹配方法:

package cn.ganlixin.guava;

import com.github.rholder.retry.RetryException;
import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;

import java.util.concurrent.ExecutionException;

public class UseRetryer {

    @Test
    public void testWhenRetry() throws ExecutionException, RetryException {
        final Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
                // 當運行結果大於10的時候,需要重試(表達式返回true,則重試)
                .retryIfResult(res -> {
                    return res > 10;
                })

                // 當拋出異常時,就會進行重試
                .retryIfException()

                // 或者當拋出ArithmeticException異常時,進行重試
                .retryIfExceptionOfType(ArithmeticException.class)

                // 如果拋出RuntimeException異常時,進行重試
                .retryIfRuntimeException()

                // 捕獲到異常,對異常進行處理,返回true時,會進行重試
                .retryIfException(exception -> {
                    System.out.println("捕獲到" + exception);
                    // 可以對異常信息、異常種類進行處理,決定是否需要重試
                    return StringUtils.contains(exception.getMessage(), "wrong");
                })

                // 重試3次
                .withStopStrategy(StopStrategies.stopAfterAttempt(3))
                .build();

        Integer res = retryer.call(() -> {
            throw new Exception();
        });

        System.out.println(res);
    }
}

  

3.2、重試次數設置

  前面說了什么情況下需要重試,那么需要重試多少次呢?

  guava retryer中,如果沒有設置重試多少次,那么將會沒有休止地一直重試(死循環),所以建議一定要設置重試次數。

package cn.ganlixin.guava;

import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import org.junit.Test;

public class UseRetryer {

    @Test
    public void testRetryStop() {
        Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
                // 拋出異常時重試
                .retryIfException()
                // 設置什么時候停止重試
                // 這里設置的是,執行3次都失敗了就停止重試
                .withStopStrategy(StopStrategies.stopAfterAttempt(3))
                .build();
    }
}

  設置停止策略,主要是使用StopStrategies類的靜態方法,如下:

// 不停止,一直重試(默認)
StopStrategies.neverStop()

// attemptNumber次失敗后,停止重試
StopStrategies.stopAfterAttempt(int attemptNumber)

// 執行多久后停止(在未到停止的時間節點前,如果失敗,會一致重試)
StopStrategies.stopAfterDelay(2, TimeUnit.SECONDS)

  

3.3、重試間隔設置

  重試時間間隔設置,是指當執行失敗后,執行下一次重試,需要等多久,這就是重試間隔策略。

  下面是一個簡單示例:

package cn.ganlixin.guava;

import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.WaitStrategies;
import org.junit.Test;

import java.util.concurrent.TimeUnit;

public class UseRetryer {

    @Test
    public void testRetryInteval() {
        Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
                // 出現異常時重試
                .retryIfException()
                // 設置重試時間間隔,此處設置固定時間間隔(2秒)
                .withWaitStrategy(WaitStrategies.fixedWait(2, TimeUnit.SECONDS))
                .build();
    }
}

  和重試次數類似,重試間隔,主要使用WaitStrategies類的靜態方法進行設置(有很多方法),常用的如下:

// 失敗后沒有間隔,立即重試(默認)
WaitStrategies.noWait()

// 固定時間間隔(3秒)
WaitStrategies.fixedWait(3, TimeUnit.SECONDS)

// 設置第一次重試的時間間隔,然后后面每次重試時間間隔的增量
incrementingWait(long initialSleepTime, TimeUnit initialSleepTimeUnit, long increment, TimeUnit incrementTimeUnit) 
WaitStrategies.incrementingWait(2, TimeUnit.SECONDS, 1, TimeUnit.SECONDS)
// 解釋:第一次重試間隔2秒,后面每次間隔時間是在前一個間隔上加1秒(就是3秒),再下一次是4秒

  

 

 

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM