feat: 1.3.0

1. 优化手动重试模块
This commit is contained in:
byteblogs168 2023-05-15 18:49:54 +08:00
parent 0e6d43681a
commit ff42df5229
9 changed files with 280 additions and 33 deletions

View File

@ -1,5 +1,6 @@
package com.aizuda.easy.retry.client.core.intercepter;
import cn.hutool.core.util.StrUtil;
import com.aizuda.easy.retry.common.core.constant.SystemConstants;
import com.aizuda.easy.retry.common.core.model.EasyRetryHeaders;
import lombok.Getter;
@ -65,6 +66,10 @@ public class RetrySiteSnapshot {
}
public static boolean isMethodEntrance(String methodEntrance) {
if (StrUtil.isBlank(getMethodEntrance())) {
return false;
}
return getMethodEntrance().equals(methodEntrance);
}
@ -109,7 +114,8 @@ public class RetrySiteSnapshot {
}
public static boolean isRetryForStatusCode() {
return Objects.nonNull(getRetryStatusCode()) && getRetryStatusCode().equals(SystemConstants.EASY_RETRY_STATUS_CODE);
return Objects.nonNull(getRetryStatusCode()) && getRetryStatusCode()
.equals(SystemConstants.EASY_RETRY_STATUS_CODE);
}
public static Long getEntryMethodTime() {
@ -124,11 +130,11 @@ public class RetrySiteSnapshot {
ENTRY_METHOD_TIME.remove();
}
public static void removeRetryHeader(){
public static void removeRetryHeader() {
RETRY_HEADER.remove();
}
public static void removeRetryStatusCode(){
public static void removeRetryStatusCode() {
RETRY_STATUS_CODE.remove();
}
@ -166,6 +172,11 @@ public class RetrySiteSnapshot {
* 远程重试阶段
*/
REMOTE(2),
/**
* 手动提交数据
*/
MANUAL_REPORT(3),
;
private final int stage;

View File

@ -1,8 +1,13 @@
package com.aizuda.easy.retry.client.core.retryer;
import cn.hutool.core.util.StrUtil;
import com.aizuda.easy.retry.client.core.RetryOperations;
import com.aizuda.easy.retry.client.core.intercepter.RetrySiteSnapshot;
import com.aizuda.easy.retry.client.core.strategy.ExecutorMethod;
import com.aizuda.easy.retry.client.core.strategy.RetryStrategy;
import com.aizuda.easy.retry.common.core.model.EasyRetryHeaders;
import java.util.Objects;
/**
* 手动生成重试任务模板类
@ -20,7 +25,20 @@ public class EasyRetryTemplate implements RetryOperations {
@Override
public void executeRetry() {
retryStrategy.openRetry(scene, executorMethodClass.getName(), params);
Integer stage = RetrySiteSnapshot.getStage();
try {
retryStrategy.openRetry(scene, executorMethodClass.getName(), params);
} finally {
// stage == null 则非嵌套重试, 需求清除线程记录的数据信息
// stage != null 则由上层调度的进行清除线程记录的数据信息
if (Objects.isNull(stage)) {
RetrySiteSnapshot.removeAll();
} else {
// 还原原始的重试阶段
RetrySiteSnapshot.setStage(stage);
}
}
}
protected void setExecutorMethodClass(

View File

@ -2,6 +2,7 @@ package com.aizuda.easy.retry.client.core.retryer;
import com.aizuda.easy.retry.client.core.strategy.ExecutorMethod;
import com.aizuda.easy.retry.client.core.strategy.LocalRetryStrategies;
import com.aizuda.easy.retry.client.core.strategy.ManualRetryStrategies;
import com.aizuda.easy.retry.client.core.strategy.RetryStrategy;
import com.aizuda.easy.retry.common.core.context.SpringContext;
@ -41,7 +42,7 @@ public class RetryTaskTemplateBuilder {
easyRetryTemplate.setParams(params);
easyRetryTemplate.setExecutorMethodClass(executorMethodClass);
easyRetryTemplate.setScene(scene);
RetryStrategy retryStrategy = SpringContext.getBeanByType(LocalRetryStrategies.class);
RetryStrategy retryStrategy = SpringContext.getBeanByType(ManualRetryStrategies.class);
easyRetryTemplate.setRetryStrategy(retryStrategy);
return easyRetryTemplate;
}

View File

@ -27,7 +27,7 @@ import java.util.function.Consumer;
public abstract class AbstractRetryStrategies implements RetryStrategy {
@Autowired
private List<EasyRetryListener> EasyRetryListeners;
private List<EasyRetryListener> easyRetryListeners;
@Override
public RetryerResultContext openRetry(String sceneName, String executorClassName, Object[] params) {
@ -52,7 +52,7 @@ public abstract class AbstractRetryStrategies implements RetryStrategy {
retryerResultContext.setRetryerInfo(retryerInfo);
try {
for (EasyRetryListener EasyRetryListener : EasyRetryListeners) {
for (EasyRetryListener EasyRetryListener : easyRetryListeners) {
EasyRetryListener.beforeRetry(sceneName, executorClassName, params);
}
@ -79,7 +79,7 @@ public abstract class AbstractRetryStrategies implements RetryStrategy {
Object result = retryerResultContext.getResult();
RetryerInfo retryerInfo = retryerResultContext.getRetryerInfo();
for (EasyRetryListener EasyRetryListener : EasyRetryListeners) {
for (EasyRetryListener EasyRetryListener : easyRetryListeners) {
EasyRetryListener.successOnRetry(result, retryerInfo.getScene(), retryerInfo.getExecutorClassName());
}
@ -99,7 +99,7 @@ public abstract class AbstractRetryStrategies implements RetryStrategy {
RetryerInfo retryerInfo = context.getRetryerInfo();
try {
for (EasyRetryListener EasyRetryListener : EasyRetryListeners) {
for (EasyRetryListener EasyRetryListener : easyRetryListeners) {
EasyRetryListener
.failureOnRetry(retryerInfo.getScene(), retryerInfo.getExecutorClassName(), throwable);
}

View File

@ -5,21 +5,21 @@ import com.aizuda.easy.retry.client.core.RetryExecutorParameter;
import com.aizuda.easy.retry.client.core.exception.EasyRetryClientException;
import com.aizuda.easy.retry.client.core.intercepter.RetrySiteSnapshot;
import com.aizuda.easy.retry.client.core.report.ReportHandler;
import com.github.rholder.retry.*;
import com.google.common.base.Predicate;
import com.aizuda.easy.retry.client.core.retryer.RetryType;
import com.aizuda.easy.retry.client.core.retryer.RetryerInfo;
import com.aizuda.easy.retry.client.core.retryer.RetryerResultContext;
import com.aizuda.easy.retry.common.core.enums.RetryResultStatusEnum;
import com.aizuda.easy.retry.common.core.log.LogUtils;
import com.github.rholder.retry.Attempt;
import com.github.rholder.retry.RetryListener;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.StopStrategy;
import com.github.rholder.retry.WaitStrategies;
import com.github.rholder.retry.WaitStrategy;
import com.google.common.base.Predicate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.util.Collections;
import java.util.List;
@ -96,7 +96,7 @@ public class LocalRetryStrategies extends AbstractRetryStrategies {
if (RetryType.LOCAL_REMOTE.name().equals(retryerInfo.getRetryType().name())){
// 上报
log.debug("上报 scene:[{}]", retryerInfo.getScene());
reportHandler.asyncReport(retryerInfo.getScene(), retryerInfo.getExecutorClassName(), params);
doReport(retryerInfo, params);
}
};
}
@ -115,21 +115,7 @@ public class LocalRetryStrategies extends AbstractRetryStrategies {
// 仅仅是远程重试则直接上报
log.debug("上报 scene:[{}]", retryerInfo.getScene());
return () -> {
if (retryerInfo.isAsync()) {
if (retryerInfo.isForceReport()) {
reportHandler.asyncReportWithForce(retryerInfo.getScene(), retryerInfo.getExecutorClassName(), params);
} else {
reportHandler.asyncReport(retryerInfo.getScene(), retryerInfo.getExecutorClassName(), params);
}
} else {
if (retryerInfo.isForceReport()) {
reportHandler.syncReport(retryerInfo.getScene(), retryerInfo.getExecutorClassName(), params, retryerInfo.getTimeout(), retryerInfo.getUnit());
} else {
reportHandler.syncReport(retryerInfo.getScene(), retryerInfo.getExecutorClassName(), params, retryerInfo.getTimeout(), retryerInfo.getUnit());
}
}
doReport(retryerInfo, params);
RetrySiteSnapshot.setStage(RetrySiteSnapshot.EnumStage.REMOTE.getStage());
return null;
};
@ -139,6 +125,31 @@ public class LocalRetryStrategies extends AbstractRetryStrategies {
}
/**
* 上报数据
*
* @param retryerInfo 定义重试场景的信息
* @param params 执行参数
*/
private void doReport(final RetryerInfo retryerInfo, final Object[] params) {
if (retryerInfo.isAsync()) {
if (retryerInfo.isForceReport()) {
reportHandler.asyncReportWithForce(retryerInfo.getScene(), retryerInfo.getExecutorClassName(), params);
} else {
reportHandler.asyncReport(retryerInfo.getScene(), retryerInfo.getExecutorClassName(), params);
}
} else {
if (retryerInfo.isForceReport()) {
reportHandler.syncReport(retryerInfo.getScene(), retryerInfo.getExecutorClassName(),
params, retryerInfo.getTimeout(), retryerInfo.getUnit());
} else {
reportHandler.syncReport(retryerInfo.getScene(), retryerInfo.getExecutorClassName(),
params, retryerInfo.getTimeout(), retryerInfo.getUnit());
}
}
}
@Override
public RetryExecutorParameter<WaitStrategy, StopStrategy> getRetryExecutorParameter(RetryerInfo retryerInfo) {

View File

@ -0,0 +1,166 @@
package com.aizuda.easy.retry.client.core.strategy;
import com.aizuda.easy.retry.client.core.RetryExecutor;
import com.aizuda.easy.retry.client.core.RetryExecutorParameter;
import com.aizuda.easy.retry.client.core.intercepter.RetrySiteSnapshot;
import com.aizuda.easy.retry.client.core.report.ReportHandler;
import com.aizuda.easy.retry.client.core.retryer.RetryType;
import com.aizuda.easy.retry.client.core.retryer.RetryerInfo;
import com.aizuda.easy.retry.client.core.retryer.RetryerResultContext;
import com.aizuda.easy.retry.common.core.enums.RetryResultStatusEnum;
import com.aizuda.easy.retry.common.core.log.LogUtils;
import com.github.rholder.retry.Attempt;
import com.github.rholder.retry.RetryListener;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.StopStrategy;
import com.github.rholder.retry.WaitStrategies;
import com.github.rholder.retry.WaitStrategy;
import com.google.common.base.Predicate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
* @author: www.byteblogs.com
* @date : 2023-05-15 18:19
*/
@Component
@Slf4j
public class ManualRetryStrategies extends AbstractRetryStrategies {
@Autowired
private ReportHandler reportHandler;
@Override
protected void setStage() {
RetrySiteSnapshot.setStage(RetrySiteSnapshot.EnumStage.MANUAL_REPORT.getStage());
}
@Override
protected Consumer<Object> doRetrySuccessConsumer(final RetryerResultContext context) {
return o -> {
LogUtils.debug(log, "ManualRetryStrategies doRetrySuccessConsumer ");
};
}
@Override
protected void error(final RetryerResultContext context) {
context.setRetryResultStatusEnum(RetryResultStatusEnum.FAILURE);
}
@Override
protected boolean preValidator(final RetryerInfo retryerInfo, final RetryerResultContext resultContext) {
if (retryerInfo.isForceReport()) {
return true;
}
if (RetrySiteSnapshot.isRunning()) {
resultContext.setRetryResultStatusEnum(RetryResultStatusEnum.FAILURE);
resultContext.setMessage("执行重试检验不通过 原因: 存在正在运行的重试任务");
return false;
}
return true;
}
@Override
protected void unexpectedError(final Exception e, final RetryerResultContext retryerResultContext) {
retryerResultContext.setRetryResultStatusEnum(RetryResultStatusEnum.FAILURE);
}
@Override
protected void success(final RetryerResultContext retryerResultContext) {
retryerResultContext.setRetryResultStatusEnum(RetryResultStatusEnum.SUCCESS);
}
@Override
protected Consumer<Throwable> doGetRetryErrorConsumer(final RetryerInfo retryerInfo, final Object[] params) {
return throwable -> {
LogUtils.debug(log, "ManualRetryStrategies doGetRetryErrorConsumer ");
};
}
@Override
protected Callable doGetCallable(final RetryExecutor<WaitStrategy, StopStrategy> retryExecutor, Object[] params) {
RetryerInfo retryerInfo = retryExecutor.getRetryerInfo();
return () -> doReport(retryerInfo, params);
}
/**
* 上报数据
*
* @param retryerInfo 定义重试场景的信息
* @param params 执行参数
*/
private boolean doReport(final RetryerInfo retryerInfo, final Object[] params) {
if (retryerInfo.isAsync()) {
if (retryerInfo.isForceReport()) {
return reportHandler
.asyncReportWithForce(retryerInfo.getScene(), retryerInfo.getExecutorClassName(), params);
} else {
return reportHandler.asyncReport(retryerInfo.getScene(), retryerInfo.getExecutorClassName(), params);
}
} else {
if (retryerInfo.isForceReport()) {
return reportHandler.syncReport(retryerInfo.getScene(), retryerInfo.getExecutorClassName(),
params, retryerInfo.getTimeout(), retryerInfo.getUnit());
} else {
return reportHandler.syncReport(retryerInfo.getScene(), retryerInfo.getExecutorClassName(),
params, retryerInfo.getTimeout(), retryerInfo.getUnit());
}
}
}
@Override
protected RetryExecutorParameter<WaitStrategy, StopStrategy> getRetryExecutorParameter(RetryerInfo retryerInfo) {
return new RetryExecutorParameter<WaitStrategy, StopStrategy>() {
@Override
public Predicate<Throwable> exceptionPredicate() {
return throwable -> ManualRetryStrategies.super.validate(throwable.getClass(), retryerInfo);
}
@Override
public WaitStrategy backOff() {
return WaitStrategies.fixedWait(500, TimeUnit.MILLISECONDS);
}
@Override
public StopStrategy stop() {
return StopStrategies.stopAfterAttempt(5);
}
@Override
public List<RetryListener> getRetryListeners() {
return Collections.singletonList(new RetryListener() {
@Override
public <V> void onRetry(Attempt<V> attempt) {
if (attempt.hasResult()) {
LogUtils.error(log, "easy-retry 手动创建重试数据成功,第[{}]次调度", attempt.getAttemptNumber());
}
if (attempt.hasException()) {
LogUtils.error(log, "easy-retry 手动创建重试数据失败,第[{}]次调度 ", attempt.getAttemptNumber(),
attempt.getExceptionCause());
}
}
});
}
};
}
@Override
public boolean supports(final int stage, final RetryType retryType) {
return RetrySiteSnapshot.EnumStage.MANUAL_REPORT.getStage() == stage;
}
}

View File

@ -14,7 +14,7 @@ import java.util.concurrent.TimeUnit;
* @date : 2022-03-07 14:07
* @since 1.3.0
*/
@ExecutorMethodRegister(scene = CustomSyncCreateTask.SCENE, async = false, timeout = 10000, unit = TimeUnit.MILLISECONDS)
@ExecutorMethodRegister(scene = CustomSyncCreateTask.SCENE, async = false, timeout = 10000, unit = TimeUnit.MILLISECONDS, forceReport = false)
@Slf4j
public class CustomSyncCreateTask implements ExecutorMethod {

View File

@ -1,10 +1,16 @@
package com.example.demo;
import com.aizuda.easy.retry.client.core.annotation.Retryable;
import com.aizuda.easy.retry.client.core.exception.EasyRetryClientException;
import com.aizuda.easy.retry.client.core.retryer.EasyRetryTemplate;
import com.aizuda.easy.retry.client.core.retryer.RetryTaskTemplateBuilder;
import com.example.model.Zoo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.Random;
import java.util.UUID;
/**
@ -22,4 +28,25 @@ public class NestMethodService {
public void testNestMethod() {
testExistsTransactionalRetryService.testSimpleInsert(UUID.randomUUID().toString());
}
@Retryable(scene = "testNestMethodForCustomSyncCreateTask" , isThrowException = false)
@Transactional
public void testNestMethodForCustomSyncCreateTask() {
Random random = new Random();
int i = random.nextInt(5);
if (i <= 2) {
throw new EasyRetryClientException("测试注解重试和手动重试");
}
Zoo zoo = new Zoo();
zoo.setNow(LocalDateTime.now());
EasyRetryTemplate retryTemplate = RetryTaskTemplateBuilder.newBuilder()
.withExecutorMethod(CustomSyncCreateTask.class)
.withParam(zoo)
.withScene(CustomSyncCreateTask.SCENE)
.build();
retryTemplate.executeRetry();
}
}

View File

@ -4,10 +4,12 @@ import com.aizuda.easy.retry.client.core.retryer.EasyRetryTemplate;
import com.aizuda.easy.retry.client.core.retryer.RetryTaskTemplateBuilder;
import com.example.demo.CustomAsyncCreateTask;
import com.example.demo.CustomSyncCreateTask;
import com.example.demo.NestMethodService;
import com.example.model.Cat;
import com.example.model.Zoo;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
@ -20,6 +22,9 @@ import java.time.LocalDateTime;
@Slf4j
public class EasyRetryTemplateTest {
@Autowired
private NestMethodService nestMethodService;
@Test
public void generateAsyncTaskTest() throws InterruptedException {
@ -52,4 +57,12 @@ public class EasyRetryTemplateTest {
retryTemplate.executeRetry();
}
@Test
public void testNestMethodForCustomSyncCreateTask() throws InterruptedException {
nestMethodService.testNestMethodForCustomSyncCreateTask();
Thread.sleep(90000);
}
}