🍌 重试机制
Forest请求在发送失败的情况下会触发重试机制,重试的次数限制、时间间隔、触发条件全部都可以配置
# 配置全局重试信息
重试属性的全局配置
# 全局配置下,所有请求的默认重试信息按此配置进行
forest:
    max-retry-count: 3     # 最大请求重试次数,默认为 0 次
    max-retry-interval: 10 # 为最大重试时间间隔, 单位为毫秒,默认为 0 毫秒
 2
3
4
5
# 全局配置下,所有请求的默认重试信息按此配置进行
# 最大请求重试次数,默认为 0 次
forest.max-retry-count=3
# 为最大重试时间间隔, 单位为毫秒,默认为 0 毫秒   
forest.max-retry-interval=10
 2
3
4
5
6
<!-- retryCount 最大请求重试次数,默认为 0 次 -->
<!-- maxRetryInterval 最大重试时间间隔, 单位为毫秒,默认为 0 毫秒 -->
<forest:configuration
    ... ...
    retryCount="3"
    maxRetryInterval="10">
... ...
</forest:configuration>
 2
3
4
5
6
7
8
// 获取全局默认配置对象
ForestConfiguration configuration = Forest.config();
// 最大请求重试次数,默认为 0 次
configuration.setMaxRetryCount(3);
// 为最大重试时间间隔, 单位为毫秒,默认为 0 毫秒
configuration.setMaxRetryInterval(10);
 2
3
4
5
6
// Make sure to add code blocks to your code group
# 使用@Retry注解
 # 在方法上挂上@Retry注解
 public interface MyClient {
    // maxRetryCount 为最大重试次数,默认为 0 次
    // maxRetryInterval 为最大重试时间间隔, 单位为毫秒,默认为 0 毫秒
    @Get("/")
    @Retry(maxRetryCount = "3", maxRetryInterval = "10")
    String sendData();
}
 2
3
4
5
6
7
这里的@Retry注解设置了两个属性:
maxRetryCount: 请求的最大重试次数,当重试次数大于该属性,将停止触发请求重试流程,默认为0次,即不会触发重试maxRetryInterval: 请求的最大重试时间间隔,单位为毫秒,默认为0毫秒,即没有时间间隔
当调用该接口的sendData()方法后,若请求失败就会不断进行重试,直到不满足重试条件为止 (即请求成功,或达到最大请求次数限制)
# 接口上使用@Retry注解
 @Retry注解也可以挂在interface接口类上,代表其下的所有请求方法都设置为此重试配置
// maxRetryCount 为最大重试次数,默认为 0 次
// maxRetryInterval 为最大重试时间间隔, 单位为毫秒,默认为 0 毫秒
// 该接口下每个方法都以此为请求重试配置
@Retry(maxRetryCount = "3", maxRetryInterval = "10")
public interface MyClient {
    
    @Get("/test1")
    String sendData1();
    @Get("/test2")
    String sendData2();
}
 2
3
4
5
6
7
8
9
10
11
12
此时,不管调用sendData1()还是sendData2()方法,都会按最大重试3次,最大重试时间间隔10ms为重试属性
# 重试器
Retryer 重试器,即重试策略,可以设定每次重试请求之间的时间间隔
Forest 默认重试器类为 com.dtflys.forest.retryer.BackOffRetryer,它是依据二进制退避算法的重试策略类
若配置该重试器,重试过程如下:
- 第一次重试与第一次请求之间间隔 0的2次方 * 1s, 即0s
 - 第二次重试与第一次重试之间间隔 1的2次方 * 1s, 即1s
 - 第三次次重试与第二次重试之间间隔 2的2次方 * 1s, 即4s
 - 后面几次重试时间间隔以此类推,直到达到最大请求次数后停止重试
 - 每次时间间隔不能大于 
maxRetryInterval, 若maxRetryInterval设置为10, 则每次间隔只能为10ms 
您也可以自定义重试器
// 自定义重试器
// 继承 BackOffRetryer 类
public class MyRetryer extends BackOffRetryer {
    public MyRetryer(ForestRequest request) {
        super(request);
    }
    /**
     * 重写 nextInterval 方法
     * 该方法用于指定每次重试的时间间隔
     * @param currentCount 当前重试次数
     * @return 时间间隔 (时间单位为毫秒)
     */
    @Override
    protected long nextInterval(int currentCount) {
        // 每次重试时间间隔恒定为 1s (1000ms)
        return 1000;
    }
}
 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
然后,再通过@Retryer注解绑定该自定义重试器类
public interface MyClient {
    // maxRetryCount 为最大重试次数,默认为 0 次
    // maxRetryInterval 为最大重试时间间隔, 单位为毫秒,默认为 0 毫秒
    // @Retryer 注解绑定自定义的 MyRetryer 重试器类
    // 将按照自定义的重试策略处理重试间隔时间
    @Get("/")
    @Retry(maxRetryCount = "3", maxRetryInterval = "10")
    @Retryer(MyRetryer.class)
    String sendData();
}
 2
3
4
5
6
7
8
9
10
@Retryer注解同样也可以挂在 interface 类上,这里不再赘述。
# 重试条件
Forest 请求的重试条件有两种设置模式:
- 将 请求成功/失败条件 作为重试条件
 - 设置 RetryWhen 重试条件
 
这两种模式分别对应于两种不同的重试流程:
# 重试流程
- 请求失败后的重试流程
 
请求失败  ✔
 └── 是否未达到请求最大重试次数 (maxRetryCount)  ✔
      ├── 执行 OnRetry 回调函数
      ├── 执行拦截器中的 onRetry 方法
      ├── 发送重试请求
      └── 回到第一步,重试请求是否成功
 2
3
4
5
6
- 请求成功后的重试流程
 
请求成功  ✔
 └── 是否满足重试条件 (自定义 RetryWhen 接口类条件)  ✔
      └── 是否未达到请求最大重试次数 (maxRetryCount)  ✔
           ├── 执行 OnRetry 回调函数
           ├── 执行拦截器中的 onRetry 方法
           ├── 发送重试请求
           └── 回到第一步,重试请求是否成功,并且是否满足重试条件
 2
3
4
5
6
7
# 使用@Success注解设置重试条件
 一般情况只会走第1种重试流程,即通过请求的成功/失败来判断是否重试,逻辑很简单:请求成功不重试,失败就重试
此时,可以配合@Success注解和@Retry注解组合使用
public interface MyClient {
    // maxRetryCount 为最大重试次数,默认为 0 次
    // maxRetryInterval 为最大重试时间间隔, 单位为毫秒,默认为 0 毫秒
    // 同时请求成功/失败/重试的判定条件
    // 设置为自定义的 MySuccessCondition 条件类
    @Get("/")
    @Retry(maxRetryCount = "3", maxRetryInterval = "10")
    @Success(condition = MySuccessCondition.class)
    String sendData();
}
 2
3
4
5
6
7
8
9
10
11
12
这种方式可以同时设置重试最大次数、间隔时间、以及自定义的成功/失败/重试条件。
# 使用 RetryWhen 接口实现重试条件
 但有些特殊情况,需要在请求成功的情况下也重试,满足一定业务条件后才停止重试,这种情况就需要 RetryWhen 重试条件上场了
先定义自定义请求重试实现类
// 自定义重试条件类
// 需要实现 RetryWhen 接口
public class MyRetryCondition implements RetryWhen {
    /**
     * 请求重试条件
     * @param req Forest请求对象
     * @param res Forest响应对象
     * @return true 重试,false 不重试
     */
    @Override
    public boolean retryWhen(ForestRequest req, ForestResponse res) {
        // 响应状态码为 203 就重试
        return res.statusIs(203);
    }
}
 2
3
4
5
6
7
8
9
10
11
12
13
14
15
然后,通过@Retry注解的condition属性指定该类
public interface MyClient {
    // maxRetryCount 为最大重试次数
    // maxRetryInterval 为最大重试时间间隔, 单位为毫秒
    @Get("/")
    @Retry(maxRetryCount = "3", maxRetryInterval = "10", condition = MyRetryCondition.class)
    String sendData();
}
 2
3
4
5
6
7
若发送请求后,服务端返回203状态码,就不断触发重试,直到服务端不返回203,或达到最大重试次数,停止重试。
若最后一次重试服务端发送的还是203,则认为请求成功,执行onSuccess。
# 拦截器onRetry方法
 拦截器的onRetry方法会在触发重试时,发送重试请求前被调用
public class MyRetryInterceptor implements Interceptor<Object> {
    /**
     * 在请重试前调用 onRetry 回调函数
     *
     * @param req Forest请求对象
     * @param res Forest响应对象
     */
    @Override
    public void onRetry(ForestRequest req, ForestResponse res) {
        // req.getCurrentRetryCount() 获取请求当前重试次数
        System.out.println("要重试了!当前重试次数:" + req.getCurrentRetryCount());
    }
}
 2
3
4
5
6
7
8
9
10
11
12
13
14
文档导航
关于如何使用拦截器,请参见《拦截器》