重试操作算法及工具封装类Retry

简介

在我们进行业务逻辑编程的时候,很多时候调用一个方法、访问一个web接口、进行一系列计算任务等,都有可能出现异常情况或者耗时情况。
这时候我们可能需要对这项操作进行重试,比如说重试三次直至该操作成功。在这样的需求下,如果每一个操作的重试实现都使用代码编写,会显得非常冗余,比如说像这样:

1
2
3
4
5
6
7
8
9
10
11
String response = http.get("http://abc.com/test/get");
if (response == null) {
response = http.get("http://abc.com/test/get");
}
if (response == null) {
response = http.get("http://abc.com/test/get");
}
if (response == null) {
response = http.get("http://abc.com/test/get");
}
System.out.println(response);

代码冗余,不美观。

在这种情况下,设计一种使用方便的算法及其工具类,显得非常必要了。

设计

原始程序流程设计框图:
image

核心代码片段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public T execute(long maxOperationWaitTime,
long retryIntervalTime,
int maxRetryTimes,
Operation<T> operation,
List<Judgement<T>> judgements) {
if (operation == null) {
throw new RuntimeException("Operation must not be null.");
}
int operationTimes = 0;
T t = null;
while (operationTimes <= maxRetryTimes) {
logger.debug(operationTimes == 0 ? "Operation: {}" : "Operation retry: {}", operationTimes);
t = waitOperate(operation, maxOperationWaitTime);
boolean shouldRetry = false;
if (judgements == null || judgements.size() == 0) {//default condition
shouldRetry = new IsNullJudgement().judge(t);
} else {
for (Judgement<T> judgement : judgements) {
shouldRetry = shouldRetry || judgement.judge(t);
}
}
if (!shouldRetry) {
break;
}
operationTimes++;
sleep(retryIntervalTime);
}
logger.debug("done.");
return t;
}

说明:

方法参数 说明
maxOperationWaitTime 单次操作最大等待时间,单次操作超过该时间则认为本次操作失败,需要重试
retryIntervalTime 两次重试之间间隔等待时间
maxRetryTimes 最大重试次数,若该值为 3,则操作次数最多为 4(包括首次尝试)
operation 操作对象
judgements 判断是否需要重试对象列表

用法示例

用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void singleTest() {
String result = new Retry<String>()
.maxOperationWaitTime(30_000)//Max operation wait time during a single operation
.retryIntervalTime(1_000)//Interval time between two operations
.maxRetryTimes(3)//Retry times when operation failed(or timeout) at the first time
.operation(() -> {
//your operation
return "success!";
})
.judgement(t -> (t == null || t.isEmpty()))//add your judgement whether the operation should be retry(Operation should return a value)
.execute();
System.out.println(result);
}

结果输出

1
success!

代码仓库

https://github.com/johnsonmoon/retry.git