提交 10be9b57 作者: 方治民

refactor: 重构重试器实现 Retriever 优化测试用例

上级 729ea163
...@@ -14,7 +14,7 @@ import com.yiring.common.annotation.DownloadResponse; ...@@ -14,7 +14,7 @@ import com.yiring.common.annotation.DownloadResponse;
import com.yiring.common.annotation.RateLimiter; import com.yiring.common.annotation.RateLimiter;
import com.yiring.common.core.I18n; import com.yiring.common.core.I18n;
import com.yiring.common.core.Result; import com.yiring.common.core.Result;
import com.yiring.common.core.RetryExecutor; import com.yiring.common.core.Retriever;
import com.yiring.common.core.Status; import com.yiring.common.core.Status;
import com.yiring.common.param.IdParam; import com.yiring.common.param.IdParam;
import com.yiring.common.param.PageParam; import com.yiring.common.param.PageParam;
...@@ -61,7 +61,7 @@ public class ExampleController { ...@@ -61,7 +61,7 @@ public class ExampleController {
final Auths auths; final Auths auths;
final UserExtensionRepository userExtensionRepository; final UserExtensionRepository userExtensionRepository;
final FileManageService fileManageService; final FileManageService fileManageService;
final RetryExecutor retryExecutor; final Retriever retriever;
@RateLimiter(count = 1) @RateLimiter(count = 1)
@Operation(summary = "Hello World") @Operation(summary = "Hello World")
...@@ -83,12 +83,12 @@ public class ExampleController { ...@@ -83,12 +83,12 @@ public class ExampleController {
// throw BusinessException.i18n("Code.1"); // throw BusinessException.i18n("Code.1");
// throw new FailStatusException(Status.BAD_REQUEST, "Code.1"); // throw new FailStatusException(Status.BAD_REQUEST, "Code.1");
// 3. 重试抛出异常 // 3. 重试抛出异常
throw retryExecutor.run( throw retriever.execute(
ctx -> { ctx -> {
throw new RuntimeException("retry test fail"); throw new RuntimeException("retry test fail");
}, },
ctx -> Status.BAD_REQUEST.exception("Code.1"), ctx -> Status.BAD_REQUEST.exception("Code.1"),
template -> RetryExecutor.setSimplePolicy(template, 3, 1000L) Retriever::defaultPolicy
); );
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
package com.yiring; package com.yiring;
import cn.hutool.core.lang.Console; import cn.hutool.core.lang.Console;
import com.yiring.common.core.RetryExecutor; import com.yiring.common.core.Retriever;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
...@@ -13,14 +13,16 @@ import org.springframework.retry.annotation.EnableRetry; ...@@ -13,14 +13,16 @@ import org.springframework.retry.annotation.EnableRetry;
@EnableRetry @EnableRetry
public class RetryTests { public class RetryTests {
RetryExecutor retry = new RetryExecutor(); Retriever retriever = new Retriever();
/** /**
* 简易重试,超过默认次数会抛出异常 * 简易重试
*/ */
@Test @Test
void def() { void def() {
Integer value = retry.run(ctx -> { Integer value = retriever.execute(ctx -> {
// eg: 可以在里面写需要重试的业务逻辑,例如:网络请求、数据库连接...
Console.log("retry test, {}", ctx.getRetryCount()); Console.log("retry test, {}", ctx.getRetryCount());
String text = "0.0"; String text = "0.0";
...@@ -34,20 +36,24 @@ public class RetryTests { ...@@ -34,20 +36,24 @@ public class RetryTests {
} }
/** /**
* 默认的退回策略 * 默认的退回策略,重试 3 次,每次间隔 1s
*/ */
@Test @Test
void recover() { void recover() {
Integer value = retry.run( Integer value = retriever.execute(
ctx -> { ctx -> {
// eg: 可以在里面写需要重试的业务逻辑,例如:网络请求、数据库连接...
Console.log("retry test, {}", ctx.getRetryCount()); Console.log("retry test, {}", ctx.getRetryCount());
throw new RuntimeException("test"); throw new RuntimeException("test");
}, },
ctx -> { ctx -> {
// eg: 可以在重试超过指定次数和规则后,返回默认值,然后业务上可以根据返回值进行相应的处理,例如:返回 null,然后判断 null 时,发送告警消息
Console.log("retry recover, {}", ctx.getRetryCount()); Console.log("retry recover, {}", ctx.getRetryCount());
return 666; return 666;
}, },
template -> RetryExecutor.setSimplePolicy(template, 2, 1000L) Retriever::defaultPolicy
); );
Console.log("[recover] retry test result: {}", value); Console.log("[recover] retry test result: {}", value);
} }
...@@ -57,17 +63,15 @@ public class RetryTests { ...@@ -57,17 +63,15 @@ public class RetryTests {
*/ */
@Test @Test
void custom() { void custom() {
Integer value = retry.run( Integer value = retriever.execute(
ctx -> { ctx -> {
// eg: 可以在里面写需要重试的业务逻辑,例如:网络请求、数据库连接...
Console.log("retry test, {}", ctx.getRetryCount()); Console.log("retry test, {}", ctx.getRetryCount());
throw new RuntimeException("test"); throw new RuntimeException("test");
}, },
ctx -> { template -> Retriever.setSimplePolicy(template, 2, 5000L)
Console.log("retry recover, {}", ctx.getRetryCount());
return null;
},
template -> RetryExecutor.setSimplePolicy(template, 2, 5000L)
); );
Console.log("[recover] retry test result: {}", value); Console.log("[custom] retry test result: {}", value);
} }
} }
...@@ -13,7 +13,7 @@ import org.springframework.retry.support.RetryTemplate; ...@@ -13,7 +13,7 @@ import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
* 重试执行器 * 重试执行器(重试者)
* 用途: 主要用于解决切面重试机制的问题,减少自定义实现 AOP 重试机制的代码量 * 用途: 主要用于解决切面重试机制的问题,减少自定义实现 AOP 重试机制的代码量
* *
* @author Jim * @author Jim
...@@ -23,7 +23,7 @@ import org.springframework.stereotype.Component; ...@@ -23,7 +23,7 @@ import org.springframework.stereotype.Component;
@Slf4j @Slf4j
@Component @Component
@EnableRetry @EnableRetry
public class RetryExecutor { public class Retriever {
/** /**
* 包装重试方法实现 * 包装重试方法实现
...@@ -33,8 +33,8 @@ public class RetryExecutor { ...@@ -33,8 +33,8 @@ public class RetryExecutor {
* @param <S> 重试业务的返回值类型 * @param <S> 重试业务的返回值类型
* @return 重试业务的返回值,例如:一个连接对象、网络请求结果 * @return 重试业务的返回值,例如:一个连接对象、网络请求结果
*/ */
public <S> S run(@NotNull RetrySupplier<S> accomplish) { public <S> S execute(@NotNull RetrySupplier<S> accomplish) {
return run(accomplish, null, null); return execute(accomplish, null, null);
} }
/** /**
...@@ -46,8 +46,8 @@ public class RetryExecutor { ...@@ -46,8 +46,8 @@ public class RetryExecutor {
* @param <S> 重试业务的返回值类型 * @param <S> 重试业务的返回值类型
* @return 重试业务的返回值,例如:一个连接对象、网络请求结果 * @return 重试业务的返回值,例如:一个连接对象、网络请求结果
*/ */
public <S> S run(@NotNull RetrySupplier<S> accomplish, Consumer<RetryTemplate> consumer) { public <S> S execute(@NotNull RetrySupplier<S> accomplish, Consumer<RetryTemplate> consumer) {
return run(accomplish, null, consumer); return execute(accomplish, null, consumer);
} }
/** /**
...@@ -59,7 +59,11 @@ public class RetryExecutor { ...@@ -59,7 +59,11 @@ public class RetryExecutor {
* @param <S> 重试业务的返回值类型 * @param <S> 重试业务的返回值类型
* @return 重试业务的返回值,例如:一个连接对象、网络请求结果 * @return 重试业务的返回值,例如:一个连接对象、网络请求结果
*/ */
public <S> S run(@NotNull RetrySupplier<S> accomplish, RetrySupplier<S> recover, Consumer<RetryTemplate> consumer) { public <S> S execute(
@NotNull RetrySupplier<S> accomplish,
RetrySupplier<S> recover,
Consumer<RetryTemplate> consumer
) {
// 创建默认的重试模板 // 创建默认的重试模板
RetryTemplate template = RetryTemplate.builder().retryOn(Exception.class).build(); RetryTemplate template = RetryTemplate.builder().retryOn(Exception.class).build();
...@@ -79,7 +83,7 @@ public class RetryExecutor { ...@@ -79,7 +83,7 @@ public class RetryExecutor {
// 没有添加保底恢复实现的情况下,抛出原始异常 // 没有添加保底恢复实现的情况下,抛出原始异常
Throwable throwable = ctx.getLastThrowable(); Throwable throwable = ctx.getLastThrowable();
log.error( log.error(
"[RetryExecutor] execute fail, retry count: {}, e: {}", "[Retriever] execute fail, retry count: {}, e: {}",
ctx.getRetryCount(), ctx.getRetryCount(),
throwable.getMessage() throwable.getMessage()
); );
...@@ -89,7 +93,17 @@ public class RetryExecutor { ...@@ -89,7 +93,17 @@ public class RetryExecutor {
} }
/** /**
* 默认的重试策略,重试 3 次,每次间隔 1s
*
* @param template 重试模板
*/
public static void defaultPolicy(RetryTemplate template) {
setSimplePolicy(template, 3, 1000L);
}
/**
* 设置简单的重试策略 * 设置简单的重试策略
* 复杂的自定义重试策略可以使用 Consumer 函数回调自行实现
* *
* @param template 重试模板 * @param template 重试模板
* @param maxAttempts 最大重试次数 * @param maxAttempts 最大重试次数
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论