mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
add RetryUtil
This commit is contained in:
@@ -1,15 +1,20 @@
|
|||||||
package org.dromara.hutool.core.util;
|
/*
|
||||||
|
* Copyright (c) 2023 looly(loolly@aliyun.com)
|
||||||
|
* Hutool is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.dromara.hutool.core.thread;
|
||||||
|
|
||||||
import org.dromara.hutool.core.array.ArrayUtil;
|
import org.dromara.hutool.core.array.ArrayUtil;
|
||||||
import org.dromara.hutool.core.thread.GlobalThreadPool;
|
|
||||||
import org.dromara.hutool.core.thread.RetryableTask;
|
|
||||||
import org.dromara.hutool.core.thread.ThreadUtil;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.function.BiPredicate;
|
import java.util.function.BiPredicate;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@@ -33,8 +38,8 @@ public class RetryUtil {
|
|||||||
* @param recover 达到最大重试次数后执行的备用方法,入参是重试过程中的异常
|
* @param recover 达到最大重试次数后执行的备用方法,入参是重试过程中的异常
|
||||||
* @param exs 指定的异常类型需要重试
|
* @param exs 指定的异常类型需要重试
|
||||||
*/
|
*/
|
||||||
@SafeVarargs
|
public static void ofException(final Runnable run, final long maxAttempts, final Duration delay,
|
||||||
public static void ofException(Runnable run, long maxAttempts, Duration delay, Runnable recover, Class<? extends Throwable>... exs) {
|
final Runnable recover, Class<? extends Throwable>... exs) {
|
||||||
if (ArrayUtil.isEmpty(exs)) {
|
if (ArrayUtil.isEmpty(exs)) {
|
||||||
exs = ArrayUtil.append(exs, RuntimeException.class);
|
exs = ArrayUtil.append(exs, RuntimeException.class);
|
||||||
}
|
}
|
||||||
@@ -61,8 +66,8 @@ public class RetryUtil {
|
|||||||
* @param <T> 结果类型
|
* @param <T> 结果类型
|
||||||
* @return 执行结果
|
* @return 执行结果
|
||||||
*/
|
*/
|
||||||
@SafeVarargs
|
public static <T> T ofException(final Supplier<T> sup, final long maxAttempts, final Duration delay,
|
||||||
public static <T> T ofException(Supplier<T> sup, long maxAttempts, Duration delay, Supplier<T> recover, Class<? extends Throwable>... exs) {
|
final Supplier<T> recover, Class<? extends Throwable>... exs) {
|
||||||
if (ArrayUtil.isEmpty(exs)) {
|
if (ArrayUtil.isEmpty(exs)) {
|
||||||
exs = ArrayUtil.append(exs, RuntimeException.class);
|
exs = ArrayUtil.append(exs, RuntimeException.class);
|
||||||
}
|
}
|
||||||
@@ -84,7 +89,8 @@ public class RetryUtil {
|
|||||||
* @param recover 达到最大重试次数后执行的备用方法,入参是重试过程中的异常
|
* @param recover 达到最大重试次数后执行的备用方法,入参是重试过程中的异常
|
||||||
* @param predicate 自定义重试条件
|
* @param predicate 自定义重试条件
|
||||||
*/
|
*/
|
||||||
public static void ofPredicate(Runnable run, long maxAttempts, Duration delay, Supplier<Void> recover, BiPredicate<Void, Throwable> predicate) {
|
public static void ofPredicate(final Runnable run, final long maxAttempts, final Duration delay,
|
||||||
|
final Supplier<Void> recover, final BiPredicate<Void, Throwable> predicate) {
|
||||||
RetryableTask.retryForPredicate(run, predicate)
|
RetryableTask.retryForPredicate(run, predicate)
|
||||||
.delay(delay)
|
.delay(delay)
|
||||||
.maxAttempts(maxAttempts)
|
.maxAttempts(maxAttempts)
|
||||||
@@ -106,7 +112,8 @@ public class RetryUtil {
|
|||||||
* @param <T> 结果类型
|
* @param <T> 结果类型
|
||||||
* @return 执行结果
|
* @return 执行结果
|
||||||
*/
|
*/
|
||||||
public static <T> T ofPredicate(Supplier<T> sup, long maxAttempts, Duration delay, Supplier<T> recover, BiPredicate<T, Throwable> predicate) {
|
public static <T> T ofPredicate(final Supplier<T> sup, final long maxAttempts, final Duration delay,
|
||||||
|
final Supplier<T> recover, final BiPredicate<T, Throwable> predicate) {
|
||||||
return RetryableTask.retryForPredicate(sup, predicate)
|
return RetryableTask.retryForPredicate(sup, predicate)
|
||||||
.delay(delay)
|
.delay(delay)
|
||||||
.maxAttempts(maxAttempts)
|
.maxAttempts(maxAttempts)
|
@@ -14,10 +14,80 @@ import static java.util.Objects.nonNull;
|
|||||||
/**
|
/**
|
||||||
* 重试任务类
|
* 重试任务类
|
||||||
*
|
*
|
||||||
|
* @param <T> 任务结果类型
|
||||||
* @author kongweiguang
|
* @author kongweiguang
|
||||||
* @since 6.0.0
|
* @since 6.0.0
|
||||||
*/
|
*/
|
||||||
public class RetryableTask<T> {
|
public class RetryableTask<T> {
|
||||||
|
|
||||||
|
// region ----- retryFor
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重试根据指定的异常,没有返回值
|
||||||
|
*
|
||||||
|
* @param <T> 返回值类型
|
||||||
|
* @param run 执行的方法 {@link Runnable}
|
||||||
|
* @param ths 指定异常 {@link Throwable},匹配任意一个异常时重试
|
||||||
|
* @return 当前对象
|
||||||
|
*/
|
||||||
|
@SafeVarargs
|
||||||
|
public static <T> RetryableTask<T> retryForExceptions(final Runnable run, final Class<? extends Throwable>... ths) {
|
||||||
|
return retryForExceptions(() -> {
|
||||||
|
run.run();
|
||||||
|
return null;
|
||||||
|
}, ths);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重试根据指定的异常,有返回值
|
||||||
|
*
|
||||||
|
* @param <T> 返回值类型
|
||||||
|
* @param sup 执行的方法 {@link Supplier}
|
||||||
|
* @param ths 指定异常 {@link Throwable},匹配任意一个异常时重试
|
||||||
|
* @return 当前对象
|
||||||
|
*/
|
||||||
|
@SafeVarargs
|
||||||
|
public static <T> RetryableTask<T> retryForExceptions(final Supplier<T> sup, final Class<? extends Throwable>... ths) {
|
||||||
|
Assert.isTrue(ths.length != 0, "exs cannot be empty");
|
||||||
|
|
||||||
|
final BiPredicate<T, Throwable> strategy = (t, e) -> {
|
||||||
|
if (nonNull(e)) {
|
||||||
|
return Arrays.stream(ths).anyMatch(ex -> ex.isAssignableFrom(e.getClass()));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
return new RetryableTask<>(sup, strategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重试根据指定的策略,没有返回值
|
||||||
|
*
|
||||||
|
* @param <T> 返回值类型
|
||||||
|
* @param run 执行的方法 {@link Runnable}
|
||||||
|
* @param predicate 策略 {@link BiPredicate},返回{@code true}时表示重试
|
||||||
|
* @return 当前对象
|
||||||
|
*/
|
||||||
|
public static <T> RetryableTask<T> retryForPredicate(final Runnable run, final BiPredicate<T, Throwable> predicate) {
|
||||||
|
return retryForPredicate(() -> {
|
||||||
|
run.run();
|
||||||
|
return null;
|
||||||
|
}, predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重试根据指定的策略,没有返回值
|
||||||
|
*
|
||||||
|
* @param <T> 返回值类型
|
||||||
|
* @param sup 执行的方法 {@link Supplier}
|
||||||
|
* @param predicate 策略 {@link BiPredicate},返回{@code true}时表示重试
|
||||||
|
* @return 当前对象
|
||||||
|
*/
|
||||||
|
public static <T> RetryableTask<T> retryForPredicate(final Supplier<T> sup, final BiPredicate<T, Throwable> predicate) {
|
||||||
|
return new RetryableTask<>(sup, predicate);
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行结果
|
* 执行结果
|
||||||
*/
|
*/
|
||||||
@@ -43,9 +113,9 @@ public class RetryableTask<T> {
|
|||||||
* 构造方法,内部使用,调用请使用请用ofXXX
|
* 构造方法,内部使用,调用请使用请用ofXXX
|
||||||
*
|
*
|
||||||
* @param sup 执行的方法
|
* @param sup 执行的方法
|
||||||
* @param predicate 策略 {@link BiPredicate}
|
* @param predicate 策略 {@link BiPredicate},返回{@code true}时表示重试
|
||||||
*/
|
*/
|
||||||
private RetryableTask(Supplier<T> sup, BiPredicate<T, Throwable> predicate) {
|
private RetryableTask(final Supplier<T> sup, final BiPredicate<T, Throwable> predicate) {
|
||||||
Assert.notNull(sup, "task parameter cannot be null");
|
Assert.notNull(sup, "task parameter cannot be null");
|
||||||
Assert.notNull(predicate, "predicate parameter cannot be null");
|
Assert.notNull(predicate, "predicate parameter cannot be null");
|
||||||
|
|
||||||
@@ -53,81 +123,13 @@ public class RetryableTask<T> {
|
|||||||
this.sup = sup;
|
this.sup = sup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重试根据指定的异常,没有返回值
|
|
||||||
*
|
|
||||||
* @param <T> 返回值类型
|
|
||||||
* @param run 执行的方法 {@link Runnable}
|
|
||||||
* @param ths 指定异常 {@link Throwable}
|
|
||||||
* @return 当前对象 {@link RetryableTask}
|
|
||||||
*/
|
|
||||||
@SafeVarargs
|
|
||||||
public static <T> RetryableTask<T> retryForExceptions(Runnable run, Class<? extends Throwable>... ths) {
|
|
||||||
return retryForExceptions(() -> {
|
|
||||||
run.run();
|
|
||||||
return null;
|
|
||||||
}, ths);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重试根据指定的策略,没有返回值
|
|
||||||
*
|
|
||||||
* @param <T> 返回值类型
|
|
||||||
* @param run 执行的方法 {@link Runnable}
|
|
||||||
* @param predicate 策略 {@link BiPredicate}
|
|
||||||
* @return 当前对象 {@link RetryableTask}
|
|
||||||
*/
|
|
||||||
public static <T> RetryableTask<T> retryForPredicate(Runnable run, BiPredicate<T, Throwable> predicate) {
|
|
||||||
return retryForPredicate(() -> {
|
|
||||||
run.run();
|
|
||||||
return null;
|
|
||||||
}, predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重试根据指定的异常,有返回值
|
|
||||||
*
|
|
||||||
* @param <T> 返回值类型
|
|
||||||
* @param sup 执行的方法 {@link Supplier}
|
|
||||||
* @param ths 指定异常 {@link Throwable}
|
|
||||||
* @return 当前对象 {@link RetryableTask}
|
|
||||||
*/
|
|
||||||
@SafeVarargs
|
|
||||||
public static <T> RetryableTask<T> retryForExceptions(Supplier<T> sup, Class<? extends Throwable>... ths) {
|
|
||||||
Assert.isTrue(ths.length != 0, "exs cannot be empty");
|
|
||||||
|
|
||||||
BiPredicate<T, Throwable> strategy = (t, e) -> {
|
|
||||||
if (nonNull(e)) {
|
|
||||||
return Arrays.stream(ths).anyMatch(ex -> ex.isAssignableFrom(e.getClass()));
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
return new RetryableTask<>(sup, strategy);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重试根据指定的策略,没有返回值
|
|
||||||
*
|
|
||||||
* @param <T> 返回值类型
|
|
||||||
* @param sup 执行的方法 {@link Supplier}
|
|
||||||
* @param predicate 策略 {@link BiPredicate}
|
|
||||||
* @return 当前对象 {@link RetryableTask}
|
|
||||||
*/
|
|
||||||
public static <T> RetryableTask<T> retryForPredicate(Supplier<T> sup, BiPredicate<T, Throwable> predicate) {
|
|
||||||
return new RetryableTask<>(sup, predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 最大重试次数
|
* 最大重试次数
|
||||||
*
|
*
|
||||||
* @param maxAttempts 次数
|
* @param maxAttempts 次数
|
||||||
* @return 当前对象 {@link RetryableTask}
|
* @return 当前对象
|
||||||
*/
|
*/
|
||||||
public RetryableTask<T> maxAttempts(long maxAttempts) {
|
public RetryableTask<T> maxAttempts(final long maxAttempts) {
|
||||||
Assert.isTrue(this.maxAttempts > 0, "maxAttempts must be greater than 0");
|
Assert.isTrue(this.maxAttempts > 0, "maxAttempts must be greater than 0");
|
||||||
|
|
||||||
this.maxAttempts = maxAttempts;
|
this.maxAttempts = maxAttempts;
|
||||||
@@ -138,9 +140,9 @@ public class RetryableTask<T> {
|
|||||||
* 重试间隔时间
|
* 重试间隔时间
|
||||||
*
|
*
|
||||||
* @param delay 间隔时间
|
* @param delay 间隔时间
|
||||||
* @return 当前对象 {@link RetryableTask}
|
* @return 当前对象
|
||||||
*/
|
*/
|
||||||
public RetryableTask<T> delay(Duration delay) {
|
public RetryableTask<T> delay(final Duration delay) {
|
||||||
Assert.notNull(this.delay, "delay parameter cannot be null");
|
Assert.notNull(this.delay, "delay parameter cannot be null");
|
||||||
|
|
||||||
this.delay = delay;
|
this.delay = delay;
|
||||||
@@ -168,7 +170,7 @@ public class RetryableTask<T> {
|
|||||||
/**
|
/**
|
||||||
* 同步执行重试方法
|
* 同步执行重试方法
|
||||||
*
|
*
|
||||||
* @return 当前对象 {@link RetryableTask}
|
* @return 当前对象
|
||||||
*/
|
*/
|
||||||
public RetryableTask<T> execute() {
|
public RetryableTask<T> execute() {
|
||||||
return doExecute();
|
return doExecute();
|
||||||
@@ -177,25 +179,25 @@ public class RetryableTask<T> {
|
|||||||
/**
|
/**
|
||||||
* 开始重试
|
* 开始重试
|
||||||
*
|
*
|
||||||
* @return 当前对象 {@link RetryableTask}
|
* @return 当前对象
|
||||||
**/
|
**/
|
||||||
private RetryableTask<T> doExecute() {
|
private RetryableTask<T> doExecute() {
|
||||||
Throwable th = null;
|
Throwable th = null;
|
||||||
|
|
||||||
while (--this.maxAttempts >= 0) {
|
while (--this.maxAttempts >= 0) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.result = this.sup.get();
|
this.result = this.sup.get();
|
||||||
} catch (Throwable t) {
|
} catch (final Throwable t) {
|
||||||
th = t;
|
th = t;
|
||||||
} finally {
|
}
|
||||||
|
|
||||||
//判断重试
|
//判断重试
|
||||||
if (this.predicate.test(this.result, th)) {
|
if (!this.predicate.test(this.result, th)) {
|
||||||
ThreadUtil.sleep(delay.toMillis());
|
// 条件不满足时,跳出
|
||||||
} else {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
ThreadUtil.sleep(delay.toMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
@@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 looly(loolly@aliyun.com)
|
||||||
|
* Hutool is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.dromara.hutool.core.thread;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.lang.Console;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
@SuppressWarnings({"NumericOverflow", "divzero"})
|
||||||
|
public class RetryUtilTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
void test() {
|
||||||
|
//自定义根据异常重试
|
||||||
|
final CompletableFuture<RetryableTask<String>> task = RetryableTask.retryForExceptions(() -> {
|
||||||
|
Console.log("1231231");
|
||||||
|
final int a = 1 / 0;
|
||||||
|
return String.valueOf(a);
|
||||||
|
}, ArithmeticException.class)
|
||||||
|
.delay(Duration.ofSeconds(1))
|
||||||
|
.maxAttempts(3)
|
||||||
|
.asyncExecute();
|
||||||
|
|
||||||
|
Assertions.assertFalse(task.isDone());
|
||||||
|
Assertions.assertEquals("兜底", task.join().get().orElseGet(() -> "兜底"));
|
||||||
|
Assertions.assertTrue(task.isDone());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
public void noReturnTest() {
|
||||||
|
//根据异常重试,没有返回值
|
||||||
|
RetryUtil.ofException(
|
||||||
|
() -> {
|
||||||
|
Console.log(123);
|
||||||
|
final int a = 1 / 0;
|
||||||
|
Console.log(a);
|
||||||
|
},
|
||||||
|
3,
|
||||||
|
Duration.ofSeconds(1),
|
||||||
|
() -> {
|
||||||
|
Console.log("兜底");
|
||||||
|
},
|
||||||
|
ArithmeticException.class
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
public void hasReturnTest() {
|
||||||
|
//根据自定义策略重试
|
||||||
|
final String result = RetryUtil.ofPredicate(
|
||||||
|
() -> {
|
||||||
|
Console.log(123);
|
||||||
|
// int a = 1 / 0;
|
||||||
|
return "ok";
|
||||||
|
},
|
||||||
|
5,
|
||||||
|
Duration.ofSeconds(1),
|
||||||
|
() -> {
|
||||||
|
Console.log("兜底");
|
||||||
|
return "do";
|
||||||
|
},
|
||||||
|
(r, e) -> {
|
||||||
|
Console.log("r = " + r);
|
||||||
|
Console.log("e = " + e);
|
||||||
|
return r.equals("ok");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Assertions.assertEquals("ok", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -1,75 +0,0 @@
|
|||||||
package org.dromara.hutool.core.util;
|
|
||||||
|
|
||||||
import org.dromara.hutool.core.thread.RetryableTask;
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
public class RetryUtilTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void test() {
|
|
||||||
//自定义根据异常重试
|
|
||||||
CompletableFuture<RetryableTask<String>> task = RetryableTask.retryForExceptions(() -> {
|
|
||||||
System.out.println("1231231");
|
|
||||||
int a = 1 / 0;
|
|
||||||
return "qqqq";
|
|
||||||
}, ArithmeticException.class)
|
|
||||||
.delay(Duration.ofSeconds(1))
|
|
||||||
.maxAttempts(3)
|
|
||||||
.asyncExecute();
|
|
||||||
|
|
||||||
Assertions.assertFalse(task.isDone());
|
|
||||||
Assertions.assertEquals("兜底", task.join().get().orElseGet(() -> {
|
|
||||||
return "兜底";
|
|
||||||
}));
|
|
||||||
Assertions.assertTrue(task.isDone());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void noReturnTest() {
|
|
||||||
//根据异常重试,没有返回值
|
|
||||||
RetryUtil.ofException(
|
|
||||||
() -> {
|
|
||||||
System.out.println(123);
|
|
||||||
int a = 1 / 0;
|
|
||||||
},
|
|
||||||
3,
|
|
||||||
Duration.ofSeconds(1),
|
|
||||||
() -> {
|
|
||||||
System.out.println("兜底");
|
|
||||||
},
|
|
||||||
ArithmeticException.class
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void hasReturnTest() {
|
|
||||||
//根据自定义策略重试
|
|
||||||
String result = RetryUtil.ofPredicate(
|
|
||||||
() -> {
|
|
||||||
System.out.println(123);
|
|
||||||
// int a = 1 / 0;
|
|
||||||
return "ok";
|
|
||||||
},
|
|
||||||
5,
|
|
||||||
Duration.ofSeconds(1),
|
|
||||||
() -> {
|
|
||||||
System.out.println("兜底");
|
|
||||||
return "do";
|
|
||||||
},
|
|
||||||
(r, e) -> {
|
|
||||||
System.out.println("r = " + r);
|
|
||||||
System.out.println("e = " + e);
|
|
||||||
return r.equals("ok");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Assertions.assertEquals("ok", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Reference in New Issue
Block a user