From 018357cadad5ea9547c235285c263e2acd9d41ce Mon Sep 17 00:00:00 2001 From: byteblogs168 <598092184@qq.com> Date: Sun, 16 Jul 2023 22:58:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=202.1.0=201.=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E6=8E=A7=E5=88=B6=E5=8F=B0=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E9=A1=B5=E9=9D=A2=202.=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E5=90=8E=E7=AB=AF=E6=97=A5=E5=BF=97=E8=A7=A3=E6=9E=90=E5=92=8C?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BB=BB=E5=8A=A1=203.=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E4=BA=86=E6=96=B0=E5=A2=9E=E4=BB=BB=E5=8A=A1=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=E5=AE=A2=E6=88=B7=E7=AB=AF=E4=B8=8A?= =?UTF-8?q?=E6=8A=A5=E3=80=81=E6=8E=A7=E5=88=B6=E5=8F=B0=E6=89=8B=E5=8A=A8?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=92=8C=E5=8D=95=E4=B8=AA=E6=96=B0=E5=A2=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../annotation/ExecutorMethodRegister.java | 7 +- .../retry/client/core/annotation/Mapping.java | 6 + .../client/core/annotation/Retryable.java | 6 +- .../core/client/netty/NettyChannel.java | 2 +- .../client/core/report/ReportListener.java | 16 +- .../strategy/AbstractRetryStrategies.java | 12 +- .../retry/server/model/dto/RetryTaskDTO.java | 2 +- easy-retry-server/pom.xml | 6 + .../server/enums/TaskGeneratorScene.java | 37 ++++ .../mybatis/mapper/RetryTaskLogMapper.java | 2 + .../mybatis/mapper/RetryTaskMapper.java | 2 + .../persistence/support/ConfigAccess.java | 2 +- .../ReportRetryInfoHttpRequestHandler.java | 45 +++- .../server/service/RetryTaskService.java | 14 +- .../service/convert/RetryTaskConverter.java | 3 + .../service/convert/TaskContextConverter.java | 23 +++ .../server/service/impl/RetryServiceImpl.java | 2 +- .../service/impl/RetryTaskServiceImpl.java | 96 ++++++--- .../support/generator/TaskGenerator.java | 29 +++ .../generator/task/AbstractGenerator.java | 195 ++++++++++++++++++ .../task/ClientReportRetryGenerator.java | 19 ++ .../task/ManaBatchRetryGenerator.java | 19 ++ .../task/ManaSingleRetryGenerator.java | 19 ++ .../support/generator/task/TaskContext.java | 57 +++++ .../web/controller/RetryTaskController.java | 13 +- .../server/web/model/request/ParseLogsVO.java | 37 ++++ .../resources/mapper/RetryTaskLogMapper.xml | 9 + .../main/resources/mapper/RetryTaskMapper.xml | 8 + frontend/src/api/manage.js | 9 + frontend/src/views/task/RetryTaskList.vue | 12 +- .../views/task/form/BatchSaveRetryTask.vue | 128 ++++++++++++ 31 files changed, 763 insertions(+), 74 deletions(-) create mode 100644 easy-retry-server/src/main/java/com/aizuda/easy/retry/server/enums/TaskGeneratorScene.java create mode 100644 easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/convert/TaskContextConverter.java create mode 100644 easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/TaskGenerator.java create mode 100644 easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/AbstractGenerator.java create mode 100644 easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/ClientReportRetryGenerator.java create mode 100644 easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/ManaBatchRetryGenerator.java create mode 100644 easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/ManaSingleRetryGenerator.java create mode 100644 easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/TaskContext.java create mode 100644 easy-retry-server/src/main/java/com/aizuda/easy/retry/server/web/model/request/ParseLogsVO.java create mode 100644 frontend/src/views/task/form/BatchSaveRetryTask.vue diff --git a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/annotation/ExecutorMethodRegister.java b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/annotation/ExecutorMethodRegister.java index 90ce8a30..414dca03 100644 --- a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/annotation/ExecutorMethodRegister.java +++ b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/annotation/ExecutorMethodRegister.java @@ -44,7 +44,7 @@ public @interface ExecutorMethodRegister { * 时刻3: 上报一个异常 idempotentId: A1 不会新增一个重试任务,会被幂等处理 * 时刻4: idempotentId: A1 重试完成, 状态为已完成 * 时刻5: 上报一个异常 idempotentId: A1 状态为重试中, 新增一条重试任务 - ** + *

* 默认的idempotentId生成器{@link SimpleIdempotentIdGenerate} 对所有参数进行MD5 * * @return idempotentId @@ -54,14 +54,13 @@ public @interface ExecutorMethodRegister { /** * 服务端重试完成(重试成功、重试到达最大次数)回调客户端 * - * @return */ Class retryCompleteCallback() default SimpleRetryCompleteCallback.class; /** * 用于标识具有业务特点的值, 比如订单号、物流编号等,可以根据具体的业务场景生成,生成规则采用通用成熟的Spel表达式进行解析 - * - * see: https://docs.spring.io/spring-framework/docs/5.0.0.M5/spring-framework-reference/html/expressions.html + *

+ * see: ... */ String bizNo() default ""; diff --git a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/annotation/Mapping.java b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/annotation/Mapping.java index 102cf478..4ea8fe16 100644 --- a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/annotation/Mapping.java +++ b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/annotation/Mapping.java @@ -20,8 +20,14 @@ import java.lang.annotation.Target; @Documented public @interface Mapping { + /** + * 请求类型 + */ RequestMethod method() default RequestMethod.GET; + /** + * 请求路径 + */ String path() default ""; } diff --git a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/annotation/Retryable.java b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/annotation/Retryable.java index a118bb69..996d8039 100644 --- a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/annotation/Retryable.java +++ b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/annotation/Retryable.java @@ -45,7 +45,6 @@ public @interface Retryable { /** * 重试处理入口,默认为原方法 * - * @return */ Class retryMethod() default ExecutorAnnotationMethod.class; @@ -60,7 +59,7 @@ public @interface Retryable { * 时刻3: 上报一个异常 idempotentId: A1 不会新增一个重试任务,会被幂等处理 * 时刻4: idempotentId: A1 重试完成, 状态为已完成 * 时刻5: 上报一个异常 idempotentId: A1 状态为重试中, 新增一条重试任务 - ** + *

* 默认的idempotentId生成器{@link SimpleIdempotentIdGenerate} 对所有参数进行MD5 * * @return idempotentId @@ -70,14 +69,13 @@ public @interface Retryable { /** * 服务端重试完成(重试成功、重试到达最大次数)回调客户端 * - * @return */ Class retryCompleteCallback() default SimpleRetryCompleteCallback.class; /** * 用于标识具有业务特点的值, 比如订单号、物流编号等,可以根据具体的业务场景生成,生成规则采用通用成熟的Spel表达式进行解析 * - * see: https://docs.spring.io/spring-framework/docs/5.0.0.M5/spring-framework-reference/html/expressions.html + * see: ... */ String bizNo() default ""; diff --git a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/netty/NettyChannel.java b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/netty/NettyChannel.java index 7443e7b5..5ecca028 100644 --- a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/netty/NettyChannel.java +++ b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/netty/NettyChannel.java @@ -50,7 +50,7 @@ public class NettyChannel { public static void send(HttpMethod method, String url, String body) throws InterruptedException { if (Objects.isNull(CHANNEL)) { - LogUtils.info(log, "send message but channel is null url:[{}] method:[{}] body:[{}] ", url, method, body); + LogUtils.error(log, "send message but channel is null url:[{}] method:[{}] body:[{}] ", url, method, body); return; } diff --git a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/report/ReportListener.java b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/report/ReportListener.java index e477a108..25b2f90c 100644 --- a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/report/ReportListener.java +++ b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/report/ReportListener.java @@ -2,13 +2,10 @@ package com.aizuda.easy.retry.client.core.report; import com.aizuda.easy.retry.client.core.RetryExecutor; import com.aizuda.easy.retry.client.core.RetryExecutorParameter; +import com.aizuda.easy.retry.client.core.cache.GroupVersionCache; import com.aizuda.easy.retry.client.core.client.NettyClient; import com.aizuda.easy.retry.client.core.client.proxy.RequestBuilder; import com.aizuda.easy.retry.client.core.config.EasyRetryProperties; -import com.aizuda.easy.retry.common.core.model.NettyResult; -import com.github.rholder.retry.*; -import com.google.common.base.Predicate; -import com.aizuda.easy.retry.client.core.cache.GroupVersionCache; import com.aizuda.easy.retry.client.core.executor.GuavaRetryExecutor; import com.aizuda.easy.retry.common.core.alarm.Alarm; import com.aizuda.easy.retry.common.core.alarm.AlarmContext; @@ -16,11 +13,13 @@ import com.aizuda.easy.retry.common.core.alarm.EasyRetryAlarmFactory; import com.aizuda.easy.retry.common.core.context.SpringContext; import com.aizuda.easy.retry.common.core.enums.NotifySceneEnum; import com.aizuda.easy.retry.common.core.log.LogUtils; +import com.aizuda.easy.retry.common.core.model.NettyResult; import com.aizuda.easy.retry.common.core.util.EnvironmentUtils; import com.aizuda.easy.retry.common.core.util.JsonUtil; import com.aizuda.easy.retry.common.core.window.Listener; import com.aizuda.easy.retry.server.model.dto.ConfigDTO; import com.aizuda.easy.retry.server.model.dto.RetryTaskDTO; +import com.github.rholder.retry.*; import lombok.extern.slf4j.Slf4j; import java.time.LocalDateTime; @@ -61,13 +60,13 @@ public class ReportListener implements Listener { try { retryExecutor.call(retryer, () -> { - LogUtils.info(log, "Batch asynchronous reporting ..."); + LogUtils.info(log, "Batch asynchronous reporting ... <|>{}<|>", JsonUtil.toJsonString(list)); CLIENT.reportRetryInfo(list); return null; }, throwable -> { - LogUtils.info(log,"Data report failed:{}", JsonUtil.toJsonString(list)); + LogUtils.error(log,"Data report failed. <|>{}<|>", JsonUtil.toJsonString(list)); sendMessage(throwable); - }, o -> LogUtils.info(log,"Data report successful retry:{}", JsonUtil.toJsonString(list))); + }, o -> LogUtils.info(log,"Data report successful retry:<|>{}<|>", JsonUtil.toJsonString(list))); } catch (Exception e) { e.printStackTrace(); } @@ -91,9 +90,6 @@ public class ReportListener implements Listener { return Collections.singletonList(new RetryListener() { @Override public void onRetry(Attempt attempt) { - if (attempt.hasResult()) { - LogUtils.error(log,"easy-retry 上报成功,第[{}]次调度", attempt.getAttemptNumber()); - } if (attempt.hasException()) { LogUtils.error(log,"easy-retry 上报失败,第[{}]次调度 ", attempt.getAttemptNumber(), attempt.getExceptionCause()); diff --git a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/strategy/AbstractRetryStrategies.java b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/strategy/AbstractRetryStrategies.java index 851d209d..9c8fb507 100644 --- a/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/strategy/AbstractRetryStrategies.java +++ b/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/strategy/AbstractRetryStrategies.java @@ -56,8 +56,8 @@ public abstract class AbstractRetryStrategies implements RetryStrategy { retryerResultContext.setRetryerInfo(retryerInfo); try { - for (EasyRetryListener EasyRetryListener : easyRetryListeners) { - EasyRetryListener.beforeRetry(sceneName, executorClassName, params); + for (EasyRetryListener easyRetryListener : easyRetryListeners) { + easyRetryListener.beforeRetry(sceneName, executorClassName, params); } Object result = retryExecutor.call(retryer, doGetCallable(retryExecutor, params), getRetryErrorConsumer(retryerResultContext, params), getRetrySuccessConsumer(retryerResultContext)); @@ -83,8 +83,8 @@ public abstract class AbstractRetryStrategies implements RetryStrategy { Object result = retryerResultContext.getResult(); RetryerInfo retryerInfo = retryerResultContext.getRetryerInfo(); - for (EasyRetryListener EasyRetryListener : easyRetryListeners) { - EasyRetryListener.successOnRetry(result, retryerInfo.getScene(), retryerInfo.getExecutorClassName()); + for (EasyRetryListener easyRetryListener : easyRetryListeners) { + easyRetryListener.successOnRetry(result, retryerInfo.getScene(), retryerInfo.getExecutorClassName()); } doRetrySuccessConsumer(retryerResultContext).accept(retryerResultContext); @@ -103,8 +103,8 @@ public abstract class AbstractRetryStrategies implements RetryStrategy { RetryerInfo retryerInfo = context.getRetryerInfo(); try { - for (EasyRetryListener EasyRetryListener : easyRetryListeners) { - EasyRetryListener + for (EasyRetryListener easyRetryListener : easyRetryListeners) { + easyRetryListener .failureOnRetry(retryerInfo.getScene(), retryerInfo.getExecutorClassName(), throwable); } } catch (Exception e) { diff --git a/easy-retry-common/easy-retry-common-server-api/src/main/java/com/aizuda/easy/retry/server/model/dto/RetryTaskDTO.java b/easy-retry-common/easy-retry-common-server-api/src/main/java/com/aizuda/easy/retry/server/model/dto/RetryTaskDTO.java index 77df9a54..94ff6bd3 100644 --- a/easy-retry-common/easy-retry-common-server-api/src/main/java/com/aizuda/easy/retry/server/model/dto/RetryTaskDTO.java +++ b/easy-retry-common/easy-retry-common-server-api/src/main/java/com/aizuda/easy/retry/server/model/dto/RetryTaskDTO.java @@ -18,7 +18,7 @@ public class RetryTaskDTO implements Serializable { /** * 加密的groupId */ - @NotBlank(message = "shardingGroupId 不能为空") + @NotBlank(message = "groupName 不能为空") @Length(max = 16, message = "组id最长为16") private String groupName; diff --git a/easy-retry-server/pom.xml b/easy-retry-server/pom.xml index ba1906ac..716fcf4e 100644 --- a/easy-retry-server/pom.xml +++ b/easy-retry-server/pom.xml @@ -137,6 +137,12 @@ org.hibernate hibernate-validator + + org.jetbrains + annotations + 13.0 + compile + diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/enums/TaskGeneratorScene.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/enums/TaskGeneratorScene.java new file mode 100644 index 00000000..5b16e910 --- /dev/null +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/enums/TaskGeneratorScene.java @@ -0,0 +1,37 @@ +package com.aizuda.easy.retry.server.enums; + +import com.aizuda.easy.retry.server.exception.EasyRetryServerException; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * id生成模式 + * + * @author www.byteblogs.com + * @date 2023-05-04 + * @since 2.0 + */ +@AllArgsConstructor +@Getter +public enum TaskGeneratorScene { + + CLIENT_REPORT(1,"客户端匹配上报"), + MANA_BATCH(2, "控制台手动批量新增"), + MANA_SINGLE(3, "控制台手动单个新增"), + ; + + private final int scene; + + private final String desc; + + public static TaskGeneratorScene modeOf(int scene) { + for (TaskGeneratorScene value : TaskGeneratorScene.values()) { + if (value.getScene() == scene) { + return value; + } + } + + throw new EasyRetryServerException("不支持的任务生成场景 [{}]", scene); + } + +} diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/persistence/mybatis/mapper/RetryTaskLogMapper.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/persistence/mybatis/mapper/RetryTaskLogMapper.java index 6696474e..528dacf8 100644 --- a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/persistence/mybatis/mapper/RetryTaskLogMapper.java +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/persistence/mybatis/mapper/RetryTaskLogMapper.java @@ -30,4 +30,6 @@ public interface RetryTaskLogMapper extends BaseMapper { @Param("endTime")LocalDateTime endTime ); + int batchInsert(List list); + } diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/persistence/mybatis/mapper/RetryTaskMapper.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/persistence/mybatis/mapper/RetryTaskMapper.java index a5b25e6e..63999190 100644 --- a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/persistence/mybatis/mapper/RetryTaskMapper.java +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/persistence/mybatis/mapper/RetryTaskMapper.java @@ -13,4 +13,6 @@ public interface RetryTaskMapper extends BaseMapper { int countAllRetryTaskByRetryStatus(@Param("partition") Integer partition, @Param("retryStatus") Integer retryStatus); + int batchInsert(List list); + } diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/persistence/support/ConfigAccess.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/persistence/support/ConfigAccess.java index 4f8a9353..a31c7043 100644 --- a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/persistence/support/ConfigAccess.java +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/persistence/support/ConfigAccess.java @@ -76,7 +76,7 @@ public interface ConfigAccess { * * @return 黑名单列表 */ - Set getBlacklist(String shardingGroupId); + Set getBlacklist(String groupName); /** * 获取所有组配置信息 diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/server/handler/ReportRetryInfoHttpRequestHandler.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/server/handler/ReportRetryInfoHttpRequestHandler.java index 3b1aada7..efca0c0a 100644 --- a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/server/handler/ReportRetryInfoHttpRequestHandler.java +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/server/handler/ReportRetryInfoHttpRequestHandler.java @@ -1,6 +1,9 @@ package com.aizuda.easy.retry.server.server.handler; +import cn.hutool.core.lang.Assert; import cn.hutool.core.net.url.UrlQuery; +import com.aizuda.easy.retry.server.enums.TaskGeneratorScene; +import com.aizuda.easy.retry.server.exception.EasyRetryServerException; import com.aizuda.easy.retry.server.model.dto.RetryTaskDTO; import com.aizuda.easy.retry.server.service.RetryService; import com.aizuda.easy.retry.server.enums.StatusEnum; @@ -8,12 +11,20 @@ import com.aizuda.easy.retry.common.core.log.LogUtils; import com.aizuda.easy.retry.common.core.model.NettyResult; import com.aizuda.easy.retry.common.core.model.EasyRetryRequest; import com.aizuda.easy.retry.common.core.util.JsonUtil; +import com.aizuda.easy.retry.server.service.convert.TaskContextConverter; +import com.aizuda.easy.retry.server.support.generator.TaskGenerator; +import com.aizuda.easy.retry.server.support.generator.task.TaskContext; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + import static com.aizuda.easy.retry.common.core.constant.SystemConstants.HTTP_PATH.BATCH_REPORT; /** @@ -28,7 +39,7 @@ import static com.aizuda.easy.retry.common.core.constant.SystemConstants.HTTP_PA public class ReportRetryInfoHttpRequestHandler extends PostHttpRequestHandler { @Autowired - private RetryService retryService; + private List taskGenerators; @Override public boolean supports(String path) { @@ -42,18 +53,38 @@ public class ReportRetryInfoHttpRequestHandler extends PostHttpRequestHandler { @Override public String doHandler(String content, UrlQuery urlQuery, HttpHeaders headers) { - LogUtils.info(log, "批量上报重试数据 content:[{}]", content); + LogUtils.info(log, "Batch Report Retry Data. content:[{}]", content); EasyRetryRequest retryRequest = JsonUtil.parseObject(content, EasyRetryRequest.class); + Object[] args = retryRequest.getArgs(); try { - Object[] args = retryRequest.getArgs(); + TaskGenerator taskGenerator = taskGenerators.stream() + .filter(t -> t.supports(TaskGeneratorScene.CLIENT_REPORT.getScene())) + .findFirst().orElseThrow(() -> new EasyRetryServerException("没有匹配的任务生成器")); - Boolean aBoolean = retryService.batchReportRetry(JsonUtil.parseList(JsonUtil.toJsonString(args[0]), RetryTaskDTO.class)); - return JsonUtil.toJsonString(new NettyResult(StatusEnum.YES.getStatus(), "批量上报重试数据处理成功", aBoolean, retryRequest.getReqId())); + Assert.notEmpty(args, () -> new EasyRetryServerException("上报的数据不能为空. reqId:[{}]", retryRequest.getReqId())); + List retryTaskList = JsonUtil.parseList(JsonUtil.toJsonString(args[0]), RetryTaskDTO.class); + + Set set = retryTaskList.stream().map(RetryTaskDTO::getGroupName).collect(Collectors.toSet()); + Assert.isTrue(set.size() <= 1, () -> new EasyRetryServerException("批量上报数据,同一批次只能是相同的组. reqId:[{}]", retryRequest.getReqId())); + + Map> map = retryTaskList.stream().collect(Collectors.groupingBy(RetryTaskDTO::getSceneName)); + + map.forEach(((sceneName, retryTaskDTOS) -> { + TaskContext taskContext = new TaskContext(); + taskContext.setSceneName(sceneName); + taskContext.setGroupName(set.stream().findFirst().get()); + taskContext.setTaskInfos(TaskContextConverter.INSTANCE.toTaskContextInfo(retryTaskList)); + + // 生成任务 + taskGenerator.taskGenerator(taskContext); + })); + + return JsonUtil.toJsonString(new NettyResult(StatusEnum.YES.getStatus(), "Batch Retry Data Upload Processed Successfully", Boolean.TRUE, retryRequest.getReqId())); } catch (Exception e) { - LogUtils.error(log, "批量上报重试数据失败", e); - return JsonUtil.toJsonString(new NettyResult(StatusEnum.YES.getStatus(), e.getMessage(), null, retryRequest.getReqId())); + LogUtils.error(log, "Batch Report Retry Data Error. <|>{}<|>", args[0], e); + return JsonUtil.toJsonString(new NettyResult(StatusEnum.YES.getStatus(), e.getMessage(), Boolean.FALSE, retryRequest.getReqId())); } } } diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/RetryTaskService.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/RetryTaskService.java index 6b37fe0a..8010590c 100644 --- a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/RetryTaskService.java +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/RetryTaskService.java @@ -1,12 +1,7 @@ package com.aizuda.easy.retry.server.service; import com.aizuda.easy.retry.server.web.model.base.PageResult; -import com.aizuda.easy.retry.server.web.model.request.BatchDeleteRetryTaskVO; -import com.aizuda.easy.retry.server.web.model.request.GenerateRetryIdempotentIdVO; -import com.aizuda.easy.retry.server.web.model.request.RetryTaskQueryVO; -import com.aizuda.easy.retry.server.web.model.request.RetryTaskUpdateStatusRequestVO; -import com.aizuda.easy.retry.server.web.model.request.RetryTaskSaveRequestVO; -import com.aizuda.easy.retry.server.web.model.request.RetryTaskUpdateExecutorNameRequestVO; +import com.aizuda.easy.retry.server.web.model.request.*; import com.aizuda.easy.retry.server.web.model.response.RetryTaskResponseVO; import java.util.List; @@ -69,4 +64,11 @@ public interface RetryTaskService { */ Integer deleteRetryTask(BatchDeleteRetryTaskVO requestVO); + /** + * 解析日志 + * + * @param parseLogsVO {@link ParseLogsVO} 解析参数模型 + * @return + */ + Integer parseLogs(ParseLogsVO parseLogsVO); } diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/convert/RetryTaskConverter.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/convert/RetryTaskConverter.java index bbcef684..8b65e6c5 100644 --- a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/convert/RetryTaskConverter.java +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/convert/RetryTaskConverter.java @@ -3,6 +3,7 @@ package com.aizuda.easy.retry.server.service.convert; import com.aizuda.easy.retry.server.model.dto.RetryTaskDTO; import com.aizuda.easy.retry.server.persistence.mybatis.po.RetryDeadLetter; import com.aizuda.easy.retry.server.persistence.mybatis.po.RetryTask; +import com.aizuda.easy.retry.server.support.generator.task.TaskContext; import com.aizuda.easy.retry.server.web.model.request.RetryTaskSaveRequestVO; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -32,4 +33,6 @@ public interface RetryTaskConverter { RetryTask toRetryTask(RetryTaskSaveRequestVO retryTaskSaveRequestVO); List toRetryTaskList(List retryTaskDTOList); + + RetryTask toRetryTask(TaskContext.TaskInfo taskInfo); } diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/convert/TaskContextConverter.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/convert/TaskContextConverter.java new file mode 100644 index 00000000..1d066082 --- /dev/null +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/convert/TaskContextConverter.java @@ -0,0 +1,23 @@ +package com.aizuda.easy.retry.server.service.convert; + +import com.aizuda.easy.retry.server.model.dto.RetryTaskDTO; +import com.aizuda.easy.retry.server.support.generator.task.TaskContext; +import com.aizuda.easy.retry.server.web.model.request.RetryTaskSaveRequestVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * @author www.byteblogs.com + * @date 2023-07-16 22:09:40 + * @since 2.1.0 + */ +@Mapper +public interface TaskContextConverter { + TaskContextConverter INSTANCE = Mappers.getMapper(TaskContextConverter.class); + + TaskContext.TaskInfo toTaskContextInfo(RetryTaskSaveRequestVO retryTaskSaveRequestVO); + + List toTaskContextInfo(List retryTasks); +} diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/impl/RetryServiceImpl.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/impl/RetryServiceImpl.java index 9223c074..dd5e7e38 100644 --- a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/impl/RetryServiceImpl.java +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/impl/RetryServiceImpl.java @@ -74,7 +74,7 @@ public class RetryServiceImpl implements RetryService { @Transactional @Override public Boolean reportRetry(RetryTaskDTO retryTaskDTO) { - LogUtils.warn(log, "received report data [{}]", JsonUtil.toJsonString(retryTaskDTO)); + LogUtils.info(log, "received report data. <|>{}<|>", JsonUtil.toJsonString(retryTaskDTO)); SceneConfig sceneConfig = configAccess.getSceneConfigByGroupNameAndSceneName(retryTaskDTO.getGroupName(), retryTaskDTO.getSceneName()); if (Objects.isNull(sceneConfig)) { diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/impl/RetryTaskServiceImpl.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/impl/RetryTaskServiceImpl.java index 89971ff9..bb49ea04 100644 --- a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/impl/RetryTaskServiceImpl.java +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/service/impl/RetryTaskServiceImpl.java @@ -5,10 +5,13 @@ import cn.hutool.core.lang.Assert; import com.aizuda.easy.retry.client.model.GenerateRetryIdempotentIdDTO; import com.aizuda.easy.retry.common.core.enums.RetryStatusEnum; import com.aizuda.easy.retry.common.core.model.Result; +import com.aizuda.easy.retry.common.core.util.JsonUtil; import com.aizuda.easy.retry.server.akka.ActorGenerator; import com.aizuda.easy.retry.server.config.RequestDataHelper; import com.aizuda.easy.retry.server.dto.RegisterNodeInfo; +import com.aizuda.easy.retry.server.enums.TaskGeneratorScene; import com.aizuda.easy.retry.server.exception.EasyRetryServerException; +import com.aizuda.easy.retry.server.model.dto.RetryTaskDTO; import com.aizuda.easy.retry.server.persistence.mybatis.mapper.RetryTaskLogMapper; import com.aizuda.easy.retry.server.persistence.mybatis.mapper.RetryTaskLogMessageMapper; import com.aizuda.easy.retry.server.persistence.mybatis.mapper.RetryTaskMapper; @@ -21,17 +24,15 @@ import com.aizuda.easy.retry.server.persistence.support.ConfigAccess; import com.aizuda.easy.retry.server.service.RetryTaskService; import com.aizuda.easy.retry.server.service.convert.RetryTaskConverter; import com.aizuda.easy.retry.server.service.convert.RetryTaskResponseVOConverter; +import com.aizuda.easy.retry.server.service.convert.TaskContextConverter; import com.aizuda.easy.retry.server.support.dispatch.actor.log.RetryTaskLogDTO; import com.aizuda.easy.retry.server.support.generator.IdGenerator; +import com.aizuda.easy.retry.server.support.generator.TaskGenerator; +import com.aizuda.easy.retry.server.support.generator.task.TaskContext; import com.aizuda.easy.retry.server.support.handler.ClientNodeAllocateHandler; import com.aizuda.easy.retry.server.support.strategy.WaitStrategies; import com.aizuda.easy.retry.server.web.model.base.PageResult; -import com.aizuda.easy.retry.server.web.model.request.BatchDeleteRetryTaskVO; -import com.aizuda.easy.retry.server.web.model.request.GenerateRetryIdempotentIdVO; -import com.aizuda.easy.retry.server.web.model.request.RetryTaskQueryVO; -import com.aizuda.easy.retry.server.web.model.request.RetryTaskUpdateStatusRequestVO; -import com.aizuda.easy.retry.server.web.model.request.RetryTaskSaveRequestVO; -import com.aizuda.easy.retry.server.web.model.request.RetryTaskUpdateExecutorNameRequestVO; +import com.aizuda.easy.retry.server.web.model.request.*; import com.aizuda.easy.retry.server.web.model.response.RetryTaskResponseVO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; @@ -42,14 +43,16 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; import org.springframework.web.client.RestTemplate; import java.text.MessageFormat; import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; +import java.util.*; import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; /** * @author www.byteblogs.com @@ -76,6 +79,8 @@ public class RetryTaskServiceImpl implements RetryTaskService { @Autowired @Qualifier("configAccessProcessor") private ConfigAccess configAccess; + @Autowired + private List taskGenerators; @Override public PageResult> getRetryTaskPage(RetryTaskQueryVO queryVO) { @@ -109,8 +114,8 @@ public class RetryTaskServiceImpl implements RetryTaskService { RequestDataHelper.setPartition(queryVO.getGroupName()); retryTaskLambdaQueryWrapper.select(RetryTask::getId, RetryTask::getBizNo, RetryTask::getIdempotentId, - RetryTask::getGroupName, RetryTask::getNextTriggerAt, RetryTask::getRetryCount, - RetryTask::getRetryStatus, RetryTask::getUpdateDt, RetryTask::getSceneName, RetryTask::getUniqueId, RetryTask::getTaskType); + RetryTask::getGroupName, RetryTask::getNextTriggerAt, RetryTask::getRetryCount, + RetryTask::getRetryStatus, RetryTask::getUpdateDt, RetryTask::getSceneName, RetryTask::getUniqueId, RetryTask::getTaskType); pageDTO = retryTaskMapper.selectPage(pageDTO, retryTaskLambdaQueryWrapper.orderByDesc(RetryTask::getCreateDt)); return new PageResult<>(pageDTO, RetryTaskResponseVOConverter.INSTANCE.toRetryTaskResponseVO(pageDTO.getRecords())); } @@ -142,7 +147,7 @@ public class RetryTaskServiceImpl implements RetryTaskService { // 若恢复重试则需要重新计算下次触发时间 if (RetryStatusEnum.RUNNING.getStatus().equals(retryStatusEnum.getStatus())) { retryTask.setNextTriggerAt( - WaitStrategies.randomWait(1, TimeUnit.SECONDS, 60, TimeUnit.SECONDS).computeRetryTime(null)); + WaitStrategies.randomWait(1, TimeUnit.SECONDS, 60, TimeUnit.SECONDS).computeRetryTime(null)); } if (RetryStatusEnum.FINISH.getStatus().equals(retryStatusEnum.getStatus())) { @@ -172,19 +177,19 @@ public class RetryTaskServiceImpl implements RetryTaskService { throw new EasyRetryServerException("重试状态错误"); } - RetryTask retryTask = RetryTaskConverter.INSTANCE.toRetryTask(retryTaskRequestVO); - retryTask.setCreateDt(LocalDateTime.now()); - retryTask.setUpdateDt(LocalDateTime.now()); + TaskGenerator taskGenerator = taskGenerators.stream() + .filter(t -> t.supports(TaskGeneratorScene.MANA_SINGLE.getScene())) + .findFirst().orElseThrow(() -> new EasyRetryServerException("没有匹配的任务生成器")); - if (StringUtils.isBlank(retryTask.getExtAttrs())) { - retryTask.setExtAttrs(StringUtils.EMPTY); - } + TaskContext taskContext = new TaskContext(); + taskContext.setSceneName(retryTaskRequestVO.getSceneName()); + taskContext.setGroupName(retryTaskRequestVO.getGroupName()); + taskContext.setTaskInfos(Collections.singletonList(TaskContextConverter.INSTANCE.toTaskContextInfo(retryTaskRequestVO))); - retryTask.setNextTriggerAt( - WaitStrategies.randomWait(1, TimeUnit.SECONDS, 60, TimeUnit.SECONDS).computeRetryTime(null)); - retryTask.setUniqueId(getIdGenerator(retryTask.getGroupName())); - RequestDataHelper.setPartition(retryTaskRequestVO.getGroupName()); - return retryTaskMapper.insert(retryTask); + // 生成任务 + taskGenerator.taskGenerator(taskContext); + + return 1; } @Override @@ -194,7 +199,7 @@ public class RetryTaskServiceImpl implements RetryTaskService { // 委托客户端生成idempotentId String url = MessageFormat - .format(URL, serverNode.getHostIp(), serverNode.getHostPort().toString(), serverNode.getContextPath()); + .format(URL, serverNode.getHostIp(), serverNode.getHostPort().toString(), serverNode.getContextPath()); GenerateRetryIdempotentIdDTO generateRetryIdempotentIdDTO = new GenerateRetryIdempotentIdDTO(); generateRetryIdempotentIdDTO.setGroup(generateRetryIdempotentIdVO.getGroupName()); @@ -222,7 +227,7 @@ public class RetryTaskServiceImpl implements RetryTaskService { // 根据重试数据id,更新执行器名称 RequestDataHelper.setPartition(requestVO.getGroupName()); return retryTaskMapper - .update(retryTask, new LambdaUpdateWrapper().in(RetryTask::getId, requestVO.getIds())); + .update(retryTask, new LambdaUpdateWrapper().in(RetryTask::getId, requestVO.getIds())); } @Override @@ -231,6 +236,47 @@ public class RetryTaskServiceImpl implements RetryTaskService { return retryTaskMapper.deleteBatchIds(requestVO.getIds()); } + @Override + public Integer parseLogs(ParseLogsVO parseLogsVO) { + + String logStr = parseLogsVO.getLogStr(); + + String patternString = "<\\|>(.*?)<\\|>"; + Pattern pattern = Pattern.compile(patternString); + Matcher matcher = pattern.matcher(logStr); + + List waitInsertList = new ArrayList<>(); + // 查找匹配的内容并输出 + while (matcher.find()) { + String extractedData = matcher.group(1); + if (StringUtils.isBlank(extractedData)) { + continue; + } + + List retryTaskList = JsonUtil.parseList(extractedData, RetryTaskDTO.class); + if (!CollectionUtils.isEmpty(retryTaskList)) { + waitInsertList.addAll(retryTaskList); + } + } + + Assert.isFalse(waitInsertList.isEmpty(), () -> new EasyRetryServerException("未找到匹配的数据")); + Assert.isTrue(waitInsertList.size() <= 500, () -> new EasyRetryServerException("最多只能处理500条数据")); + + TaskGenerator taskGenerator = taskGenerators.stream() + .filter(t -> t.supports(TaskGeneratorScene.MANA_BATCH.getScene())) + .findFirst().orElseThrow(() -> new EasyRetryServerException("没有匹配的任务生成器")); + + TaskContext taskContext = new TaskContext(); + taskContext.setSceneName(parseLogsVO.getSceneName()); + taskContext.setGroupName(parseLogsVO.getGroupName()); + taskContext.setTaskInfos(TaskContextConverter.INSTANCE.toTaskContextInfo(waitInsertList)); + + // 生成任务 + taskGenerator.taskGenerator(taskContext); + + return waitInsertList.size(); + } + /** * 获取分布式id * diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/TaskGenerator.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/TaskGenerator.java new file mode 100644 index 00000000..a4cea93b --- /dev/null +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/TaskGenerator.java @@ -0,0 +1,29 @@ +package com.aizuda.easy.retry.server.support.generator; + +import com.aizuda.easy.retry.server.support.generator.task.TaskContext; + +/** + * 任务生成器 + * + * @author www.byteblogs.com + * @date 2023-07-16 11:42:38 + * @since 2.1.0 + */ +public interface TaskGenerator { + + /** + * 获取匹配的模式 + * + * @param scene 1. 客户端上报 2.控制台新增单个任务 3.控制台批量新增任务 + * @return 符合条件的生成器 + */ + boolean supports(int scene); + + /** + * 任务生成器 + * + * @param taskContext 任务列表 + * @return 成功处理的数据量 + */ + void taskGenerator(TaskContext taskContext); +} diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/AbstractGenerator.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/AbstractGenerator.java new file mode 100644 index 00000000..195f0874 --- /dev/null +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/AbstractGenerator.java @@ -0,0 +1,195 @@ +package com.aizuda.easy.retry.server.support.generator.task; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.Pair; +import com.aizuda.easy.retry.common.core.log.LogUtils; +import com.aizuda.easy.retry.common.core.util.JsonUtil; +import com.aizuda.easy.retry.server.config.RequestDataHelper; +import com.aizuda.easy.retry.server.enums.DelayLevelEnum; +import com.aizuda.easy.retry.server.enums.StatusEnum; +import com.aizuda.easy.retry.server.enums.TaskTypeEnum; +import com.aizuda.easy.retry.server.exception.EasyRetryServerException; +import com.aizuda.easy.retry.server.model.dto.RetryTaskDTO; +import com.aizuda.easy.retry.server.persistence.mybatis.mapper.*; +import com.aizuda.easy.retry.server.persistence.mybatis.po.GroupConfig; +import com.aizuda.easy.retry.server.persistence.mybatis.po.RetryTask; +import com.aizuda.easy.retry.server.persistence.mybatis.po.RetryTaskLog; +import com.aizuda.easy.retry.server.persistence.mybatis.po.SceneConfig; +import com.aizuda.easy.retry.server.persistence.support.ConfigAccess; +import com.aizuda.easy.retry.server.persistence.support.RetryTaskAccess; +import com.aizuda.easy.retry.server.service.convert.RetryTaskConverter; +import com.aizuda.easy.retry.server.service.convert.RetryTaskLogConverter; +import com.aizuda.easy.retry.server.support.generator.IdGenerator; +import com.aizuda.easy.retry.server.support.generator.TaskGenerator; +import com.aizuda.easy.retry.server.support.strategy.WaitStrategies; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.google.common.collect.Sets; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * @author www.byteblogs.com + * @date 2023-07-16 11:52:39 + * @since 2.1.0 + */ +@Slf4j +public abstract class AbstractGenerator implements TaskGenerator { + + @Autowired + @Qualifier("configAccessProcessor") + private ConfigAccess configAccess; + @Autowired + private List idGeneratorList; + @Autowired + private RetryTaskMapper retryTaskMapper; + @Autowired + private SceneConfigMapper sceneConfigMapper; + @Autowired + private RetryTaskLogMapper retryTaskLogMapper; + + @Override + @Transactional + public void taskGenerator(TaskContext taskContext) { + LogUtils.info(log, "received report data. {}", JsonUtil.toJsonString(taskContext)); + + checkAndInitScene(taskContext); + + List taskInfos = taskContext.getTaskInfos(); + + Set idempotentIdSet = taskInfos.stream().map(TaskContext.TaskInfo::getIdempotentId).collect(Collectors.toSet()); + + // 获取相关的任务,用户幂等校验 + List retryTasks = retryTaskMapper.selectList(new LambdaQueryWrapper() + .eq(RetryTask::getGroupName, taskContext.getGroupName()) + .eq(RetryTask::getSceneName, taskContext.getSceneName()) + .in(RetryTask::getIdempotentId, idempotentIdSet)); + + Map> retryTaskMap = retryTasks.stream().collect(Collectors.groupingBy(RetryTask::getIdempotentId)); + + List waitInsertTasks = new ArrayList<>(); + List waitInsertTaskLogs = new ArrayList<>(); + LocalDateTime now = LocalDateTime.now(); + for (TaskContext.TaskInfo taskInfo : taskInfos) { + Pair, List> pair = doConvertTask(retryTaskMap, taskContext, now, taskInfo); + waitInsertTasks.addAll(pair.getKey()); + waitInsertTaskLogs.addAll(pair.getValue()); + } + + RequestDataHelper.setPartition(taskContext.getGroupName()); + Assert.isTrue(waitInsertTasks.size() == retryTaskMapper.batchInsert(waitInsertTasks), () -> new EasyRetryServerException("failed to report data")); + Assert.isTrue(waitInsertTaskLogs.size() == retryTaskLogMapper.batchInsert(waitInsertTaskLogs), + () -> new EasyRetryServerException("新增重试日志失败")); + } + + /** + * @param retryTaskMap + * @param now + * @param taskInfo + */ + private Pair, List> doConvertTask(Map> retryTaskMap, + TaskContext taskContext, LocalDateTime now, + TaskContext.TaskInfo taskInfo) { + List waitInsertTasks = new ArrayList<>(); + List waitInsertTaskLogs = new ArrayList<>(); + + // 判断是否存在与幂等ID相同的任务 + List list = retryTaskMap.get(taskInfo.getIdempotentId()).stream() + .filter(retryTask -> taskContext.getGroupName().equals(retryTask.getGroupName()) + && taskContext.getSceneName().equals(retryTask.getSceneName())).collect(Collectors.toList()); + // 说明存在相同的任务 + if (!CollectionUtils.isEmpty(list)) { + LogUtils.warn(log, "interrupted reporting in retrying task. [{}]", JsonUtil.toJsonString(taskInfo)); + return Pair.of(waitInsertTasks, waitInsertTaskLogs); + } + + RetryTask retryTask = RetryTaskConverter.INSTANCE.toRetryTask(taskInfo); + retryTask.setUniqueId(getIdGenerator(taskContext.getGroupName())); + retryTask.setTaskType(TaskTypeEnum.RETRY.getType()); + retryTask.setGroupName(taskContext.getGroupName()); + retryTask.setSceneName(taskContext.getSceneName()); + retryTask.setCreateDt(now); + retryTask.setUpdateDt(now); + + if (StringUtils.isBlank(retryTask.getExtAttrs())) { + retryTask.setExtAttrs(StringUtils.EMPTY); + } + + retryTask.setNextTriggerAt(WaitStrategies.randomWait(1, TimeUnit.SECONDS, 60, TimeUnit.SECONDS).computeRetryTime(null)); + waitInsertTasks.add(retryTask); + + // 初始化日志 + RetryTaskLog retryTaskLog = RetryTaskLogConverter.INSTANCE.toRetryTask(retryTask); + retryTaskLog.setTaskType(TaskTypeEnum.RETRY.getType()); + retryTaskLog.setCreateDt(now); + waitInsertTaskLogs.add(retryTaskLog); + + return Pair.of(waitInsertTasks, waitInsertTaskLogs); + } + + private void checkAndInitScene( TaskContext taskContext) { + SceneConfig sceneConfig = configAccess.getSceneConfigByGroupNameAndSceneName(taskContext.getGroupName(), taskContext.getSceneName()); + if (Objects.isNull(sceneConfig)) { + + GroupConfig groupConfig = configAccess.getGroupConfigByGroupName(taskContext.getGroupName()); + if (Objects.isNull(groupConfig)) { + throw new EasyRetryServerException("failed to report data, no group configuration found. groupName:[{}]", taskContext.getGroupName()); + } + + if (groupConfig.getInitScene().equals(StatusEnum.NO.getStatus())) { + throw new EasyRetryServerException("failed to report data, no scene configuration found. groupName:[{}] sceneName:[{}]", taskContext.getGroupName(), taskContext.getSceneName()); + } else { + // 若配置了默认初始化场景配置,则发现上报数据的时候未配置场景,默认生成一个场景 + initScene(taskContext.getGroupName(), taskContext.getSceneName()); + } + } + + } + + /** + * 若配置了默认初始化场景配置,则发现上报数据的时候未配置场景,默认生成一个场景 + * backOff(退避策略): 等级策略 + * maxRetryCount(最大重试次数): 26 + * triggerInterval(间隔时间): see: {@link DelayLevelEnum} + * + * @param groupName 组名称 + * @param sceneName 场景名称 + */ + private void initScene(String groupName, String sceneName) { + SceneConfig sceneConfig; + sceneConfig = new SceneConfig(); + sceneConfig.setGroupName(groupName); + sceneConfig.setSceneName(sceneName); + sceneConfig.setSceneStatus(StatusEnum.YES.getStatus()); + sceneConfig.setBackOff(WaitStrategies.WaitStrategyEnum.DELAY_LEVEL.getBackOff()); + sceneConfig.setMaxRetryCount(DelayLevelEnum._21.getLevel()); + sceneConfig.setDescription("自动初始化场景"); + Assert.isTrue(1 == sceneConfigMapper.insert(sceneConfig), () -> new EasyRetryServerException("init scene error")); + } + + /** + * 获取分布式id + * + * @param groupName 组id + * @return 分布式id + */ + private String getIdGenerator(String groupName) { + + GroupConfig groupConfig = configAccess.getGroupConfigByGroupName(groupName); + for (final IdGenerator idGenerator : idGeneratorList) { + if (idGenerator.supports(groupConfig.getIdGeneratorMode())) { + return idGenerator.idGenerator(groupName); + } + } + + throw new EasyRetryServerException("id generator mode not configured. [{}]", groupName); + } +} diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/ClientReportRetryGenerator.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/ClientReportRetryGenerator.java new file mode 100644 index 00000000..63023125 --- /dev/null +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/ClientReportRetryGenerator.java @@ -0,0 +1,19 @@ +package com.aizuda.easy.retry.server.support.generator.task; + +import com.aizuda.easy.retry.server.enums.TaskGeneratorScene; +import org.springframework.stereotype.Component; + +/** + * 客户端上报任务生成器 + * + * @author www.byteblogs.com + * @date 2023-07-16 11:51:56 + * @since 2.1.0 + */ +@Component +public class ClientReportRetryGenerator extends AbstractGenerator { + @Override + public boolean supports(int scene) { + return TaskGeneratorScene.CLIENT_REPORT.getScene() == scene; + } +} diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/ManaBatchRetryGenerator.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/ManaBatchRetryGenerator.java new file mode 100644 index 00000000..0dbf8ed0 --- /dev/null +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/ManaBatchRetryGenerator.java @@ -0,0 +1,19 @@ +package com.aizuda.easy.retry.server.support.generator.task; + +import com.aizuda.easy.retry.server.enums.TaskGeneratorScene; +import org.springframework.stereotype.Component; + +/** + * 控制台手动批量新增 + * + * @author www.byteblogs.com + * @date 2023-07-16 11:51:56 + * @since 2.1.0 + */ +@Component +public class ManaBatchRetryGenerator extends AbstractGenerator { + @Override + public boolean supports(int scene) { + return TaskGeneratorScene.MANA_BATCH.getScene() == scene; + } +} diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/ManaSingleRetryGenerator.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/ManaSingleRetryGenerator.java new file mode 100644 index 00000000..83813728 --- /dev/null +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/ManaSingleRetryGenerator.java @@ -0,0 +1,19 @@ +package com.aizuda.easy.retry.server.support.generator.task; + +import com.aizuda.easy.retry.server.enums.TaskGeneratorScene; +import org.springframework.stereotype.Component; + +/** + * 控制台手动单个新增 + * + * @author www.byteblogs.com + * @date 2023-07-16 11:51:56 + * @since 2.1.0 + */ +@Component +public class ManaSingleRetryGenerator extends AbstractGenerator { + @Override + public boolean supports(int scene) { + return TaskGeneratorScene.MANA_SINGLE.getScene() == scene; + } +} diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/TaskContext.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/TaskContext.java new file mode 100644 index 00000000..fa5a027a --- /dev/null +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/support/generator/task/TaskContext.java @@ -0,0 +1,57 @@ +package com.aizuda.easy.retry.server.support.generator.task; + +import lombok.Data; + +import java.util.List; + +/** + * @author www.byteblogs.com + * @date 2023-07-16 21:26:52 + * @since + */ +@Data +public class TaskContext { + + /** + * 加密的groupId + */ + private String groupName; + + /** + * 加密的sceneId + */ + private String sceneName; + + /** + * 任务信息 + */ + private List taskInfos; + + @Data + public static class TaskInfo { + /** + * 业务唯一id + */ + private String idempotentId; + + /** + * 执行器名称 + */ + private String executorName; + + /** + * 业务唯一编号 + */ + private String bizNo; + + /** + * 客户端上报参数 + */ + private String argsStr; + + /** + * 额外扩展参数 + */ + private String extAttrs; + } +} diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/web/controller/RetryTaskController.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/web/controller/RetryTaskController.java index e775f2c5..e40dcc8d 100644 --- a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/web/controller/RetryTaskController.java +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/web/controller/RetryTaskController.java @@ -4,12 +4,7 @@ import com.aizuda.easy.retry.common.core.model.Result; import com.aizuda.easy.retry.server.service.RetryTaskService; import com.aizuda.easy.retry.server.web.annotation.LoginRequired; import com.aizuda.easy.retry.server.web.model.base.PageResult; -import com.aizuda.easy.retry.server.web.model.request.BatchDeleteRetryTaskVO; -import com.aizuda.easy.retry.server.web.model.request.GenerateRetryIdempotentIdVO; -import com.aizuda.easy.retry.server.web.model.request.RetryTaskQueryVO; -import com.aizuda.easy.retry.server.web.model.request.RetryTaskUpdateStatusRequestVO; -import com.aizuda.easy.retry.server.web.model.request.RetryTaskSaveRequestVO; -import com.aizuda.easy.retry.server.web.model.request.RetryTaskUpdateExecutorNameRequestVO; +import com.aizuda.easy.retry.server.web.model.request.*; import com.aizuda.easy.retry.server.web.model.response.RetryTaskResponseVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; @@ -80,4 +75,10 @@ public class RetryTaskController { public Integer deleteRetryTask(@RequestBody @Validated BatchDeleteRetryTaskVO requestVO) { return retryTaskService.deleteRetryTask(requestVO); } + + @LoginRequired + @PostMapping("/batch") + public Integer parseLogs(@RequestBody @Validated ParseLogsVO parseLogsVO) { + return retryTaskService.parseLogs(parseLogsVO); + } } diff --git a/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/web/model/request/ParseLogsVO.java b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/web/model/request/ParseLogsVO.java new file mode 100644 index 00000000..ad64056f --- /dev/null +++ b/easy-retry-server/src/main/java/com/aizuda/easy/retry/server/web/model/request/ParseLogsVO.java @@ -0,0 +1,37 @@ +package com.aizuda.easy.retry.server.web.model.request; + +import lombok.Data; +import org.hibernate.validator.constraints.NotBlank; + +import javax.validation.constraints.NotNull; + +/** + * 解析参数模型 + * + * @author: www.byteblogs.com + * @date: 2023-07-15 23:15 + */ +@Data +public class ParseLogsVO { + + /** + * 客户端打印的上报日志信息 + */ + @NotBlank(message = "日志信息不能为空") + private String logStr; + + /** + * 组名称 + */ + @NotBlank(message = "组名称不能为空") + private String groupName; + + /** + * 场景名称 + */ + @NotBlank(message = "场景名称不能为空") + private String sceneName; + + @NotNull(message = "重试状态不能为空") + private Integer retryStatus; +} diff --git a/easy-retry-server/src/main/resources/mapper/RetryTaskLogMapper.xml b/easy-retry-server/src/main/resources/mapper/RetryTaskLogMapper.xml index d2388266..288c27f7 100644 --- a/easy-retry-server/src/main/resources/mapper/RetryTaskLogMapper.xml +++ b/easy-retry-server/src/main/resources/mapper/RetryTaskLogMapper.xml @@ -86,4 +86,13 @@ + + + + INSERT INTO retry_task_log (unique_id, group_name, scene_name, idempotent_id, biz_no, executor_name, args_str, ext_attrs, retry_status, task_type, create_dt) + VALUES + + (#{item.uniqueId}, #{item.groupName}, #{item.sceneName}, #{item.idempotentId}, #{item.bizNo}, #{item.executorName}, #{item.argsStr}, #{item.extAttrs}, #{item.retryStatus}, #{item.taskType}, #{item.createDt}) + + diff --git a/easy-retry-server/src/main/resources/mapper/RetryTaskMapper.xml b/easy-retry-server/src/main/resources/mapper/RetryTaskMapper.xml index 1e42f7e4..dbebd0a6 100644 --- a/easy-retry-server/src/main/resources/mapper/RetryTaskMapper.xml +++ b/easy-retry-server/src/main/resources/mapper/RetryTaskMapper.xml @@ -68,4 +68,12 @@ from retry_task_${partition} + + + INSERT INTO retry_task_${partition} (unique_id, group_name, scene_name, idempotent_id, biz_no, executor_name, args_str, ext_attrs, next_trigger_at, retry_count, retry_status, task_type, create_dt, update_dt) + VALUES + + (#{item.uniqueId}, #{item.groupName}, #{item.sceneName}, #{item.idempotentId}, #{item.bizNo}, #{item.executorName}, #{item.argsStr}, #{item.extAttrs}, #{item.nextTriggerAt}, #{item.retryCount}, #{item.retryStatus}, #{item.taskType}, #{item.createDt}, #{item.updateDt}) + + diff --git a/frontend/src/api/manage.js b/frontend/src/api/manage.js index 0d536f9a..7148fa82 100644 --- a/frontend/src/api/manage.js +++ b/frontend/src/api/manage.js @@ -14,6 +14,7 @@ const api = { retryTaskPage: '/retry-task/list', retryTaskById: '/retry-task/', saveRetryTask: '/retry-task', + batchSaveRetryTask: '/retry-task/batch', idempotentIdGenerate: '/retry-task/generate/idempotent-id', batchUpdate: '/retry-task/batch', deleteRetryTask: '/retry-task/batch', @@ -115,6 +116,14 @@ export function saveRetryTask (data) { }) } +export function batchSaveRetryTask (data) { + return request({ + url: api.batchSaveRetryTask, + method: 'post', + data + }) +} + export function getTotalPartition () { return request({ url: api.totalPartition, diff --git a/frontend/src/views/task/RetryTaskList.vue b/frontend/src/views/task/RetryTaskList.vue index 3b4a5644..6ed9add7 100644 --- a/frontend/src/views/task/RetryTaskList.vue +++ b/frontend/src/views/task/RetryTaskList.vue @@ -66,7 +66,8 @@

- 新增 + 单个 + 批量 删除 @@ -115,6 +116,8 @@ + + @@ -125,6 +128,7 @@ import { getAllGroupNameList, getRetryTaskPage, getSceneList, updateRetryTaskSta import { STable } from '@/components' import SaveRetryTask from './form/SaveRetryTask' import BatchUpdateRetryTaskInfo from './form/BatchUpdateRetryTaskInfo' +import BatchSaveRetryTask from '@/views/task/form/BatchSaveRetryTask.vue' export default { name: 'RetryTask', @@ -133,7 +137,8 @@ export default { ATextarea, STable, SaveRetryTask, - BatchUpdateRetryTaskInfo + BatchUpdateRetryTaskInfo, + BatchSaveRetryTask }, data () { return { @@ -285,6 +290,9 @@ export default { handleNew () { this.$refs.saveRetryTask.isShow(true, null) }, + handleBatchNew () { + this.$refs.batchSaveRetryTask.isShow(true, null) + }, handleChange (value) { getSceneList({ groupName: value }).then((res) => { this.sceneList = res.data diff --git a/frontend/src/views/task/form/BatchSaveRetryTask.vue b/frontend/src/views/task/form/BatchSaveRetryTask.vue new file mode 100644 index 00000000..5a06118e --- /dev/null +++ b/frontend/src/views/task/form/BatchSaveRetryTask.vue @@ -0,0 +1,128 @@ + + + + +