feat: 1.5.0
1. 回调支持持久化
This commit is contained in:
parent
03ba7592b2
commit
2b5803c65a
@ -43,6 +43,7 @@ CREATE TABLE `retry_dead_letter_0`
|
|||||||
`executor_name` varchar(512) NOT NULL DEFAULT '' COMMENT '执行器名称',
|
`executor_name` varchar(512) NOT NULL DEFAULT '' COMMENT '执行器名称',
|
||||||
`args_str` text NOT NULL COMMENT '执行方法参数',
|
`args_str` text NOT NULL COMMENT '执行方法参数',
|
||||||
`ext_attrs` text NOT NULL COMMENT '扩展字段',
|
`ext_attrs` text NOT NULL COMMENT '扩展字段',
|
||||||
|
`task_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '任务类型 1、重试数据 2、回调数据',
|
||||||
`create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `idx_group_name_scene_name` (`group_name`, `scene_name`),
|
KEY `idx_group_name_scene_name` (`group_name`, `scene_name`),
|
||||||
@ -66,6 +67,7 @@ CREATE TABLE `retry_task_0`
|
|||||||
`next_trigger_at` datetime NOT NULL COMMENT '下次触发时间',
|
`next_trigger_at` datetime NOT NULL COMMENT '下次触发时间',
|
||||||
`retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '重试次数',
|
`retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '重试次数',
|
||||||
`retry_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '重试状态 0、重试中 1、成功 2、最大重试次数',
|
`retry_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '重试状态 0、重试中 1、成功 2、最大重试次数',
|
||||||
|
`task_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '任务类型 1、重试数据 2、回调数据',
|
||||||
`create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
`update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
`update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
@ -89,6 +91,7 @@ CREATE TABLE `retry_task_log`
|
|||||||
`args_str` text NOT NULL COMMENT '执行方法参数',
|
`args_str` text NOT NULL COMMENT '执行方法参数',
|
||||||
`ext_attrs` text NOT NULL COMMENT '扩展字段',
|
`ext_attrs` text NOT NULL COMMENT '扩展字段',
|
||||||
`retry_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '重试状态 0、失败 1、成功',
|
`retry_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '重试状态 0、失败 1、成功',
|
||||||
|
`task_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '任务类型 1、重试数据 2、回调数据',
|
||||||
`create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
`update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
`update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||||
`error_message` text NOT NULL COMMENT '异常信息',
|
`error_message` text NOT NULL COMMENT '异常信息',
|
||||||
|
@ -61,4 +61,19 @@ public interface SystemConstants {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface CALL_BACK {
|
||||||
|
/**
|
||||||
|
* 回调id前缀
|
||||||
|
*/
|
||||||
|
String CB_ = "CB_";
|
||||||
|
/**
|
||||||
|
* 最大重试次数
|
||||||
|
*/
|
||||||
|
int MAX_RETRY_COUNT = 288;
|
||||||
|
/**
|
||||||
|
* 间隔时间
|
||||||
|
*/
|
||||||
|
int TRIGGER_INTERVAL = 15 * 60;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.aizuda.easy.retry.common.core.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author www.byteblogs.com
|
||||||
|
* @date 2023-06-04
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public enum TaskTypeEnum {
|
||||||
|
RETRY(1),
|
||||||
|
CALLBACK(2);
|
||||||
|
|
||||||
|
private final Integer type;
|
||||||
|
}
|
@ -2,7 +2,7 @@ package com.aizuda.easy.retry.server.akka;
|
|||||||
|
|
||||||
import akka.actor.ActorRef;
|
import akka.actor.ActorRef;
|
||||||
import akka.actor.ActorSystem;
|
import akka.actor.ActorSystem;
|
||||||
import com.aizuda.easy.retry.server.support.dispatch.actor.callback.CallbackRetryResultActor;
|
import com.aizuda.easy.retry.server.support.dispatch.actor.exec.ExecCallbackUnitActor;
|
||||||
import com.aizuda.easy.retry.server.support.dispatch.actor.exec.ExecUnitActor;
|
import com.aizuda.easy.retry.server.support.dispatch.actor.exec.ExecUnitActor;
|
||||||
import com.aizuda.easy.retry.server.support.dispatch.actor.result.FailureActor;
|
import com.aizuda.easy.retry.server.support.dispatch.actor.result.FailureActor;
|
||||||
import com.aizuda.easy.retry.server.support.dispatch.actor.result.FinishActor;
|
import com.aizuda.easy.retry.server.support.dispatch.actor.result.FinishActor;
|
||||||
@ -53,7 +53,7 @@ public class ActorGenerator {
|
|||||||
* @return actor 引用
|
* @return actor 引用
|
||||||
*/
|
*/
|
||||||
public static ActorRef callbackRetryResultActor() {
|
public static ActorRef callbackRetryResultActor() {
|
||||||
return getDispatchResultActorSystem().actorOf(getSpringExtension().props(CallbackRetryResultActor.BEAN_NAME));
|
return getDispatchResultActorSystem().actorOf(getSpringExtension().props(ExecCallbackUnitActor.BEAN_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,6 +29,8 @@ public class RetryDeadLetter implements Serializable {
|
|||||||
|
|
||||||
private String extAttrs;
|
private String extAttrs;
|
||||||
|
|
||||||
|
private Integer taskType;
|
||||||
|
|
||||||
private LocalDateTime createDt;
|
private LocalDateTime createDt;
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
@ -37,6 +37,8 @@ public class RetryTask implements Serializable {
|
|||||||
|
|
||||||
private Integer retryStatus;
|
private Integer retryStatus;
|
||||||
|
|
||||||
|
private Integer taskType;
|
||||||
|
|
||||||
private LocalDateTime createDt;
|
private LocalDateTime createDt;
|
||||||
|
|
||||||
private LocalDateTime updateDt;
|
private LocalDateTime updateDt;
|
||||||
|
@ -31,6 +31,8 @@ public class RetryTaskLog implements Serializable {
|
|||||||
|
|
||||||
private Integer retryStatus;
|
private Integer retryStatus;
|
||||||
|
|
||||||
|
private Integer taskType;
|
||||||
|
|
||||||
private String errorMessage;
|
private String errorMessage;
|
||||||
|
|
||||||
private LocalDateTime createDt;
|
private LocalDateTime createDt;
|
||||||
|
@ -14,7 +14,7 @@ public interface RetryTaskAccess<T> {
|
|||||||
/**
|
/**
|
||||||
* 批量查询重试任务
|
* 批量查询重试任务
|
||||||
*/
|
*/
|
||||||
List<T> listAvailableTasks(String groupName, LocalDateTime lastAt, Integer pageSize);
|
List<T> listAvailableTasks(String groupName, LocalDateTime lastAt, Integer pageSize, Integer taskType);
|
||||||
|
|
||||||
List<T> listRetryTaskByRetryCount(String groupName, Integer retryStatus);
|
List<T> listRetryTaskByRetryCount(String groupName, Integer retryStatus);
|
||||||
|
|
||||||
|
@ -30,12 +30,14 @@ public class MybatisRetryTaskAccess extends AbstractRetryTaskAccess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RetryTask> listAvailableTasks(String groupName, LocalDateTime lastAt, Integer pageSize) {
|
public List<RetryTask> listAvailableTasks(String groupName, LocalDateTime lastAt, Integer pageSize, Integer taskType) {
|
||||||
setPartition(groupName);
|
setPartition(groupName);
|
||||||
return retryTaskMapper.selectPage(new PageDTO<>(0, pageSize),
|
return retryTaskMapper.selectPage(new PageDTO<>(0, pageSize),
|
||||||
new LambdaQueryWrapper<RetryTask>()
|
new LambdaQueryWrapper<RetryTask>()
|
||||||
.eq(RetryTask::getRetryStatus, RetryStatusEnum.RUNNING.getStatus())
|
.eq(RetryTask::getRetryStatus, RetryStatusEnum.RUNNING.getStatus())
|
||||||
.eq(RetryTask::getGroupName, groupName).ge(RetryTask::getCreateDt, lastAt)
|
.eq(RetryTask::getGroupName, groupName)
|
||||||
|
.eq(RetryTask::getTaskType, taskType)
|
||||||
|
.ge(RetryTask::getCreateDt, lastAt)
|
||||||
.orderByAsc(RetryTask::getCreateDt)).getRecords();
|
.orderByAsc(RetryTask::getCreateDt)).getRecords();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ public class RetryTaskAccessProcessor implements RetryTaskAccess<RetryTask> {
|
|||||||
* 批量查询重试任务
|
* 批量查询重试任务
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<RetryTask> listAvailableTasks(String groupName, LocalDateTime lastAt, Integer pageSize) {
|
public List<RetryTask> listAvailableTasks(String groupName, LocalDateTime lastAt, Integer pageSize, Integer taskType) {
|
||||||
return retryTaskAccesses.listAvailableTasks(groupName, lastAt, pageSize);
|
return retryTaskAccesses.listAvailableTasks(groupName, lastAt, pageSize, taskType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -19,6 +19,8 @@ public interface RetryTaskConverter {
|
|||||||
|
|
||||||
RetryTask toRetryTask(RetryTaskDTO retryTaskDTO);
|
RetryTask toRetryTask(RetryTaskDTO retryTaskDTO);
|
||||||
|
|
||||||
|
RetryTask toRetryTask(RetryTask retryTask);
|
||||||
|
|
||||||
RetryTask toRetryTask(RetryTaskSaveRequestVO retryTaskSaveRequestVO);
|
RetryTask toRetryTask(RetryTaskSaveRequestVO retryTaskSaveRequestVO);
|
||||||
|
|
||||||
List<RetryTask> toRetryTaskList(List<RetryTaskDTO> retryTaskDTOList);
|
List<RetryTask> toRetryTaskList(List<RetryTaskDTO> retryTaskDTOList);
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package com.aizuda.easy.retry.server.support;
|
package com.aizuda.easy.retry.server.support;
|
||||||
|
|
||||||
import com.aizuda.easy.retry.server.persistence.mybatis.po.RetryTask;
|
import com.aizuda.easy.retry.server.persistence.mybatis.po.RetryTask;
|
||||||
|
import com.aizuda.easy.retry.server.persistence.mybatis.po.ServerNode;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author: www.byteblogs.com
|
* @author: www.byteblogs.com
|
||||||
@ -42,4 +45,10 @@ public interface RetryContext<V> {
|
|||||||
* @param waitStrategy {@link WaitStrategy} 等待策略
|
* @param waitStrategy {@link WaitStrategy} 等待策略
|
||||||
*/
|
*/
|
||||||
void setWaitStrategy(WaitStrategy waitStrategy);
|
void setWaitStrategy(WaitStrategy waitStrategy);
|
||||||
|
|
||||||
|
ServerNode getServerNode();
|
||||||
|
|
||||||
|
Set<String> getSceneBlacklist();
|
||||||
|
|
||||||
|
V getCallResult();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
package com.aizuda.easy.retry.server.support.context;
|
||||||
|
|
||||||
|
import com.aizuda.easy.retry.server.persistence.mybatis.po.RetryTask;
|
||||||
|
import com.aizuda.easy.retry.server.persistence.mybatis.po.ServerNode;
|
||||||
|
import com.aizuda.easy.retry.server.support.RetryContext;
|
||||||
|
import com.aizuda.easy.retry.server.support.WaitStrategy;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author www.byteblogs.com
|
||||||
|
* @date 2023-06-04
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CallbackRetryContext<V> implements RetryContext<V> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知客户端回调结果
|
||||||
|
*/
|
||||||
|
private V callResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异常信息
|
||||||
|
*/
|
||||||
|
private Exception exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 等待策略
|
||||||
|
*/
|
||||||
|
private WaitStrategy waitStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前重试数据
|
||||||
|
*/
|
||||||
|
private RetryTask retryTask;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 目前处理关闭的场景
|
||||||
|
*/
|
||||||
|
private Set<String> sceneBlacklist;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要调度的节点
|
||||||
|
*/
|
||||||
|
private ServerNode serverNode;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasException() {
|
||||||
|
return Objects.nonNull(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -56,6 +56,7 @@ public class DispatchService implements Lifecycle {
|
|||||||
* MAX_ID_MAP[key] = group 的 idHash MAX_ID_MAP[value] = retry_task的 create_at时间
|
* MAX_ID_MAP[key] = group 的 idHash MAX_ID_MAP[value] = retry_task的 create_at时间
|
||||||
*/
|
*/
|
||||||
public static final Map<String, LocalDateTime> LAST_AT_MAP = new HashMap<>();
|
public static final Map<String, LocalDateTime> LAST_AT_MAP = new HashMap<>();
|
||||||
|
public static final Map<String, LocalDateTime> LAST_AT_CALL_BACK_MAP = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调度时长
|
* 调度时长
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
package com.aizuda.easy.retry.server.support.dispatch.actor.callback;
|
|
||||||
|
|
||||||
import akka.actor.AbstractActor;
|
|
||||||
import cn.hutool.core.util.IdUtil;
|
|
||||||
import com.aizuda.easy.retry.client.model.RetryCallbackDTO;
|
|
||||||
import com.aizuda.easy.retry.common.core.constant.SystemConstants;
|
|
||||||
import com.aizuda.easy.retry.common.core.log.LogUtils;
|
|
||||||
import com.aizuda.easy.retry.common.core.model.Result;
|
|
||||||
import com.aizuda.easy.retry.common.core.model.EasyRetryHeaders;
|
|
||||||
import com.aizuda.easy.retry.common.core.util.JsonUtil;
|
|
||||||
import com.aizuda.easy.retry.server.persistence.mybatis.po.RetryTask;
|
|
||||||
import com.aizuda.easy.retry.server.persistence.mybatis.po.ServerNode;
|
|
||||||
import com.aizuda.easy.retry.server.support.handler.ClientNodeAllocateHandler;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
|
||||||
import org.springframework.http.HttpEntity;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author: www.byteblogs.com
|
|
||||||
* @date : 2023-01-10 08:50
|
|
||||||
*/
|
|
||||||
@Component("CallbackRetryResultActor")
|
|
||||||
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
|
||||||
@Slf4j
|
|
||||||
public class CallbackRetryResultActor extends AbstractActor {
|
|
||||||
|
|
||||||
public static final String BEAN_NAME = "CallbackRetryResultActor";
|
|
||||||
public static final String URL = "http://{0}:{1}/{2}/retry/callback/v1";
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RestTemplate restTemplate;
|
|
||||||
@Autowired
|
|
||||||
private ClientNodeAllocateHandler clientNodeAllocateHandler;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Receive createReceive() {
|
|
||||||
return receiveBuilder().match(RetryTask.class, retryTask->{
|
|
||||||
|
|
||||||
try {
|
|
||||||
ServerNode serverNode = clientNodeAllocateHandler.getServerNode(retryTask.getGroupName());
|
|
||||||
if (Objects.isNull(serverNode)) {
|
|
||||||
LogUtils.warn(log, "暂无可用的客户端节点");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 回调参数
|
|
||||||
RetryCallbackDTO retryCallbackDTO = new RetryCallbackDTO();
|
|
||||||
retryCallbackDTO.setIdempotentId(retryTask.getIdempotentId());
|
|
||||||
retryCallbackDTO.setRetryStatus(retryTask.getRetryStatus());
|
|
||||||
retryCallbackDTO.setArgsStr(retryTask.getArgsStr());
|
|
||||||
retryCallbackDTO.setScene(retryTask.getSceneName());
|
|
||||||
retryCallbackDTO.setGroup(retryTask.getGroupName());
|
|
||||||
retryCallbackDTO.setExecutorName(retryTask.getExecutorName());
|
|
||||||
retryCallbackDTO.setUniqueId(retryTask.getUniqueId());
|
|
||||||
|
|
||||||
// 设置header
|
|
||||||
HttpHeaders requestHeaders = new HttpHeaders();
|
|
||||||
EasyRetryHeaders easyRetryHeaders = new EasyRetryHeaders();
|
|
||||||
easyRetryHeaders.setEasyRetry(Boolean.TRUE);
|
|
||||||
easyRetryHeaders.setEasyRetryId(retryTask.getUniqueId());
|
|
||||||
requestHeaders.add(SystemConstants.EASY_RETRY_HEAD_KEY, JsonUtil.toJsonString(easyRetryHeaders));
|
|
||||||
|
|
||||||
HttpEntity<RetryCallbackDTO> requestEntity = new HttpEntity<>(retryCallbackDTO, requestHeaders);
|
|
||||||
|
|
||||||
String format = MessageFormat.format(URL, serverNode.getHostIp(), serverNode.getHostPort().toString(), serverNode.getContextPath());
|
|
||||||
Result result = restTemplate.postForObject(format, requestEntity, Result.class);
|
|
||||||
LogUtils.info(log, "回调请求客户端 response:[{}}] ", JsonUtil.toJsonString(result));
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
getContext().stop(getSelf());
|
|
||||||
}
|
|
||||||
|
|
||||||
}).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,151 @@
|
|||||||
|
package com.aizuda.easy.retry.server.support.dispatch.actor.exec;
|
||||||
|
|
||||||
|
import akka.actor.AbstractActor;
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import com.aizuda.easy.retry.client.model.DispatchRetryDTO;
|
||||||
|
import com.aizuda.easy.retry.client.model.DispatchRetryResultDTO;
|
||||||
|
import com.aizuda.easy.retry.client.model.RetryCallbackDTO;
|
||||||
|
import com.aizuda.easy.retry.common.core.constant.SystemConstants;
|
||||||
|
import com.aizuda.easy.retry.common.core.log.LogUtils;
|
||||||
|
import com.aizuda.easy.retry.common.core.model.EasyRetryHeaders;
|
||||||
|
import com.aizuda.easy.retry.common.core.model.Result;
|
||||||
|
import com.aizuda.easy.retry.common.core.util.JsonUtil;
|
||||||
|
import com.aizuda.easy.retry.server.exception.EasyRetryServerException;
|
||||||
|
import com.aizuda.easy.retry.server.persistence.mybatis.mapper.RetryTaskLogMapper;
|
||||||
|
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.ServerNode;
|
||||||
|
import com.aizuda.easy.retry.server.service.convert.RetryTaskLogConverter;
|
||||||
|
import com.aizuda.easy.retry.server.support.IdempotentStrategy;
|
||||||
|
import com.aizuda.easy.retry.server.support.context.CallbackRetryContext;
|
||||||
|
import com.aizuda.easy.retry.server.support.context.MaxAttemptsPersistenceRetryContext;
|
||||||
|
import com.aizuda.easy.retry.server.support.retry.RetryExecutor;
|
||||||
|
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.beans.factory.config.ConfigurableBeanFactory;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重试结果执行器
|
||||||
|
*
|
||||||
|
* @author www.byteblogs.com
|
||||||
|
* @date 2021-10-30
|
||||||
|
* @since 1.5.0
|
||||||
|
*/
|
||||||
|
@Component(ExecCallbackUnitActor.BEAN_NAME)
|
||||||
|
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||||
|
@Slf4j
|
||||||
|
public class ExecCallbackUnitActor extends AbstractActor {
|
||||||
|
|
||||||
|
public static final String BEAN_NAME = "ExecCallbackUnitActor";
|
||||||
|
public static final String URL = "http://{0}:{1}/{2}/retry/callback/v1";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("bitSetIdempotentStrategyHandler")
|
||||||
|
private IdempotentStrategy<String, Integer> idempotentStrategy;
|
||||||
|
@Autowired
|
||||||
|
private RetryTaskLogMapper retryTaskLogMapper;
|
||||||
|
@Autowired
|
||||||
|
private RestTemplate restTemplate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Receive createReceive() {
|
||||||
|
return receiveBuilder().match(RetryExecutor.class, retryExecutor -> {
|
||||||
|
|
||||||
|
CallbackRetryContext context = (CallbackRetryContext) retryExecutor.getRetryContext();
|
||||||
|
RetryTask retryTask = context.getRetryTask();
|
||||||
|
ServerNode serverNode = context.getServerNode();
|
||||||
|
|
||||||
|
RetryTaskLog retryTaskLog = RetryTaskLogConverter.INSTANCE.toRetryTask(retryTask);
|
||||||
|
retryTaskLog.setErrorMessage(StringUtils.EMPTY);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (Objects.nonNull(serverNode)) {
|
||||||
|
retryExecutor.call((Callable<Result<Void>>) () -> callClient(retryTask, retryTaskLog, serverNode));
|
||||||
|
if (context.hasException()) {
|
||||||
|
retryTaskLog.setErrorMessage(context.getException().getMessage());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
retryTaskLog.setErrorMessage("暂无可用的客户端POD");
|
||||||
|
}
|
||||||
|
|
||||||
|
}catch (Exception e) {
|
||||||
|
LogUtils.error(log, "回调客户端失败 retryTask:[{}]", JsonUtil.toJsonString(retryTask), e);
|
||||||
|
retryTaskLog.setErrorMessage(StringUtils.isBlank(e.getMessage()) ? StringUtils.EMPTY : e.getMessage());
|
||||||
|
} finally {
|
||||||
|
|
||||||
|
// 清除幂等标识位
|
||||||
|
idempotentStrategy.clear(retryTask.getGroupName(), retryTask.getId().intValue());
|
||||||
|
getContext().stop(getSelf());
|
||||||
|
|
||||||
|
// 记录重试日志
|
||||||
|
retryTaskLog.setCreateDt(LocalDateTime.now());
|
||||||
|
retryTaskLog.setId(null);
|
||||||
|
Assert.isTrue(1 == retryTaskLogMapper.insert(retryTaskLog),
|
||||||
|
() -> new EasyRetryServerException("新增重试日志失败"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用客户端
|
||||||
|
*
|
||||||
|
* @param retryTask {@link RetryTask} 需要重试的数据
|
||||||
|
* @return 重试结果返回值
|
||||||
|
*/
|
||||||
|
private Result<Void> callClient(RetryTask retryTask, RetryTaskLog retryTaskLog, ServerNode serverNode) {
|
||||||
|
|
||||||
|
// 回调参数
|
||||||
|
RetryCallbackDTO retryCallbackDTO = new RetryCallbackDTO();
|
||||||
|
retryCallbackDTO.setIdempotentId(retryTask.getIdempotentId());
|
||||||
|
retryCallbackDTO.setRetryStatus(retryTask.getRetryStatus());
|
||||||
|
retryCallbackDTO.setArgsStr(retryTask.getArgsStr());
|
||||||
|
retryCallbackDTO.setScene(retryTask.getSceneName());
|
||||||
|
retryCallbackDTO.setGroup(retryTask.getGroupName());
|
||||||
|
retryCallbackDTO.setExecutorName(retryTask.getExecutorName());
|
||||||
|
retryCallbackDTO.setUniqueId(retryTask.getUniqueId());
|
||||||
|
|
||||||
|
// 设置header
|
||||||
|
HttpHeaders requestHeaders = new HttpHeaders();
|
||||||
|
EasyRetryHeaders easyRetryHeaders = new EasyRetryHeaders();
|
||||||
|
easyRetryHeaders.setEasyRetry(Boolean.TRUE);
|
||||||
|
easyRetryHeaders.setEasyRetryId(retryTask.getUniqueId());
|
||||||
|
requestHeaders.add(SystemConstants.EASY_RETRY_HEAD_KEY, JsonUtil.toJsonString(easyRetryHeaders));
|
||||||
|
|
||||||
|
HttpEntity<RetryCallbackDTO> requestEntity = new HttpEntity<>(retryCallbackDTO, requestHeaders);
|
||||||
|
|
||||||
|
String format = MessageFormat.format(URL, serverNode.getHostIp(), serverNode.getHostPort().toString(), serverNode.getContextPath());
|
||||||
|
Result result = restTemplate.postForObject(format, requestEntity, Result.class);
|
||||||
|
LogUtils.info(log, "回调请求客户端 response:[{}}] ", JsonUtil.toJsonString(result));
|
||||||
|
|
||||||
|
if (1 != result.getStatus() && StringUtils.isNotBlank(result.getMessage())) {
|
||||||
|
retryTaskLog.setErrorMessage(result.getMessage());
|
||||||
|
} else {
|
||||||
|
DispatchRetryResultDTO data = JsonUtil.parseObject(JsonUtil.toJsonString(result.getData()), DispatchRetryResultDTO.class);
|
||||||
|
result.setData(data);
|
||||||
|
if (Objects.nonNull(data) && StringUtils.isNotBlank(data.getExceptionMsg())) {
|
||||||
|
retryTaskLog.setErrorMessage(data.getExceptionMsg());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
LogUtils.info(log, "请求客户端 response:[{}}] ", JsonUtil.toJsonString(result));
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -125,7 +125,7 @@ public class ExecUnitActor extends AbstractActor {
|
|||||||
HttpEntity<DispatchRetryDTO> requestEntity = new HttpEntity<>(dispatchRetryDTO, requestHeaders);
|
HttpEntity<DispatchRetryDTO> requestEntity = new HttpEntity<>(dispatchRetryDTO, requestHeaders);
|
||||||
|
|
||||||
String format = MessageFormat.format(URL, serverNode.getHostIp(), serverNode.getHostPort().toString(), serverNode.getContextPath());
|
String format = MessageFormat.format(URL, serverNode.getHostIp(), serverNode.getHostPort().toString(), serverNode.getContextPath());
|
||||||
Result result = restTemplate.postForObject(format, requestEntity, Result.class);
|
Result<DispatchRetryResultDTO> result = restTemplate.postForObject(format, requestEntity, Result.class);
|
||||||
|
|
||||||
if (1 != result.getStatus() && StringUtils.isNotBlank(result.getMessage())) {
|
if (1 != result.getStatus() && StringUtils.isNotBlank(result.getMessage())) {
|
||||||
retryTaskLog.setErrorMessage(result.getMessage());
|
retryTaskLog.setErrorMessage(result.getMessage());
|
||||||
|
@ -3,6 +3,9 @@ package com.aizuda.easy.retry.server.support.dispatch.actor.result;
|
|||||||
import akka.actor.AbstractActor;
|
import akka.actor.AbstractActor;
|
||||||
import akka.actor.ActorRef;
|
import akka.actor.ActorRef;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import com.aizuda.easy.retry.common.core.constant.SystemConstants;
|
||||||
|
import com.aizuda.easy.retry.common.core.enums.TaskTypeEnum;
|
||||||
|
import com.aizuda.easy.retry.server.support.handler.CallbackRetryTaskHandler;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
|
||||||
import com.aizuda.easy.retry.common.core.enums.RetryStatusEnum;
|
import com.aizuda.easy.retry.common.core.enums.RetryStatusEnum;
|
||||||
@ -21,6 +24,9 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
|||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.TransactionStatus;
|
||||||
|
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -45,13 +51,15 @@ public class FailureActor extends AbstractActor {
|
|||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("retryTaskAccessProcessor")
|
@Qualifier("retryTaskAccessProcessor")
|
||||||
private RetryTaskAccess<RetryTask> retryTaskAccess;
|
private RetryTaskAccess<RetryTask> retryTaskAccess;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("configAccessProcessor")
|
@Qualifier("configAccessProcessor")
|
||||||
private ConfigAccess configAccess;
|
private ConfigAccess configAccess;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RetryTaskLogMapper retryTaskLogMapper;
|
private RetryTaskLogMapper retryTaskLogMapper;
|
||||||
|
@Autowired
|
||||||
|
private CallbackRetryTaskHandler callbackRetryTaskHandler;
|
||||||
|
@Autowired
|
||||||
|
private TransactionTemplate transactionTemplate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Receive createReceive() {
|
public Receive createReceive() {
|
||||||
@ -62,19 +70,28 @@ public class FailureActor extends AbstractActor {
|
|||||||
SceneConfig sceneConfig =
|
SceneConfig sceneConfig =
|
||||||
configAccess.getSceneConfigByGroupNameAndSceneName(retryTask.getGroupName(), retryTask.getSceneName());
|
configAccess.getSceneConfigByGroupNameAndSceneName(retryTask.getGroupName(), retryTask.getSceneName());
|
||||||
|
|
||||||
ActorRef actorRef = null;
|
|
||||||
if (sceneConfig.getMaxRetryCount() <= retryTask.getRetryCount()) {
|
|
||||||
retryTask.setRetryStatus(RetryStatusEnum.MAX_RETRY_COUNT.getStatus());
|
|
||||||
actorRef = ActorGenerator.callbackRetryResultActor();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
retryTaskAccess.updateRetryTask(retryTask);
|
|
||||||
|
|
||||||
// 重试成功回调客户端
|
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||||
if (Objects.nonNull(actorRef)) {
|
@Override
|
||||||
actorRef.tell(retryTask, actorRef);
|
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||||
}
|
|
||||||
|
Integer maxRetryCount;
|
||||||
|
if (TaskTypeEnum.CALLBACK.getType().equals(retryTask.getTaskType())) {
|
||||||
|
maxRetryCount = SystemConstants.CALL_BACK.MAX_RETRY_COUNT;
|
||||||
|
} else {
|
||||||
|
maxRetryCount = sceneConfig.getMaxRetryCount();
|
||||||
|
// 创建一个回调任务
|
||||||
|
callbackRetryTaskHandler.create(retryTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxRetryCount <= retryTask.getRetryCount()) {
|
||||||
|
retryTask.setRetryStatus(RetryStatusEnum.MAX_RETRY_COUNT.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
retryTaskAccess.updateRetryTask(retryTask);
|
||||||
|
}
|
||||||
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtils.error(log,"更新重试任务失败", e);
|
LogUtils.error(log,"更新重试任务失败", e);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -3,6 +3,10 @@ package com.aizuda.easy.retry.server.support.dispatch.actor.result;
|
|||||||
import akka.actor.AbstractActor;
|
import akka.actor.AbstractActor;
|
||||||
import akka.actor.ActorRef;
|
import akka.actor.ActorRef;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import com.aizuda.easy.retry.common.core.enums.TaskTypeEnum;
|
||||||
|
import com.aizuda.easy.retry.server.service.convert.RetryTaskConverter;
|
||||||
|
import com.aizuda.easy.retry.server.support.handler.CallbackRetryTaskHandler;
|
||||||
|
import com.aizuda.easy.retry.server.support.strategy.WaitStrategies;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
|
||||||
import com.aizuda.easy.retry.common.core.enums.RetryStatusEnum;
|
import com.aizuda.easy.retry.common.core.enums.RetryStatusEnum;
|
||||||
@ -14,14 +18,23 @@ 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.RetryTaskLog;
|
||||||
import com.aizuda.easy.retry.server.persistence.support.RetryTaskAccess;
|
import com.aizuda.easy.retry.server.persistence.support.RetryTaskAccess;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.TransactionStatus;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.transaction.support.TransactionCallback;
|
||||||
|
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重试完成执行器
|
* 重试完成执行器
|
||||||
@ -42,9 +55,12 @@ public class FinishActor extends AbstractActor {
|
|||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("retryTaskAccessProcessor")
|
@Qualifier("retryTaskAccessProcessor")
|
||||||
private RetryTaskAccess<RetryTask> retryTaskAccess;
|
private RetryTaskAccess<RetryTask> retryTaskAccess;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RetryTaskLogMapper retryTaskLogMapper;
|
private RetryTaskLogMapper retryTaskLogMapper;
|
||||||
|
@Autowired
|
||||||
|
private CallbackRetryTaskHandler callbackRetryTaskHandler;
|
||||||
|
@Autowired
|
||||||
|
private TransactionTemplate transactionTemplate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Receive createReceive() {
|
public Receive createReceive() {
|
||||||
@ -54,11 +70,18 @@ public class FinishActor extends AbstractActor {
|
|||||||
retryTask.setRetryStatus(RetryStatusEnum.FINISH.getStatus());
|
retryTask.setRetryStatus(RetryStatusEnum.FINISH.getStatus());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
retryTaskAccess.updateRetryTask(retryTask);
|
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||||
|
@Override
|
||||||
|
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||||
|
retryTaskAccess.updateRetryTask(retryTask);
|
||||||
|
|
||||||
|
if (TaskTypeEnum.CALLBACK.getType().equals(retryTask.getTaskType())) {
|
||||||
|
// 创建一个回调任务
|
||||||
|
callbackRetryTaskHandler.create(retryTask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 重试成功回调客户端
|
|
||||||
ActorRef actorRef = ActorGenerator.callbackRetryResultActor();
|
|
||||||
actorRef.tell(retryTask, actorRef);
|
|
||||||
}catch (Exception e) {
|
}catch (Exception e) {
|
||||||
LogUtils.error(log, "更新重试任务失败", e);
|
LogUtils.error(log, "更新重试任务失败", e);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -0,0 +1,162 @@
|
|||||||
|
package com.aizuda.easy.retry.server.support.dispatch.actor.scan;
|
||||||
|
|
||||||
|
import akka.actor.AbstractActor;
|
||||||
|
import akka.actor.ActorRef;
|
||||||
|
import com.aizuda.easy.retry.client.model.DispatchRetryResultDTO;
|
||||||
|
import com.aizuda.easy.retry.common.core.enums.TaskTypeEnum;
|
||||||
|
import com.aizuda.easy.retry.common.core.log.LogUtils;
|
||||||
|
import com.aizuda.easy.retry.common.core.model.Result;
|
||||||
|
import com.aizuda.easy.retry.server.akka.ActorGenerator;
|
||||||
|
import com.aizuda.easy.retry.server.config.SystemProperties;
|
||||||
|
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.support.ConfigAccess;
|
||||||
|
import com.aizuda.easy.retry.server.persistence.support.RetryTaskAccess;
|
||||||
|
import com.aizuda.easy.retry.server.support.IdempotentStrategy;
|
||||||
|
import com.aizuda.easy.retry.server.support.WaitStrategy;
|
||||||
|
import com.aizuda.easy.retry.server.support.context.CallbackRetryContext;
|
||||||
|
import com.aizuda.easy.retry.server.support.context.MaxAttemptsPersistenceRetryContext;
|
||||||
|
import com.aizuda.easy.retry.server.support.dispatch.DispatchService;
|
||||||
|
import com.aizuda.easy.retry.server.support.handler.ClientNodeAllocateHandler;
|
||||||
|
import com.aizuda.easy.retry.server.support.retry.RetryBuilder;
|
||||||
|
import com.aizuda.easy.retry.server.support.retry.RetryExecutor;
|
||||||
|
import com.aizuda.easy.retry.server.support.strategy.FilterStrategies;
|
||||||
|
import com.aizuda.easy.retry.server.support.strategy.StopStrategies;
|
||||||
|
import com.aizuda.easy.retry.server.support.strategy.WaitStrategies;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author www.byteblogs.com
|
||||||
|
* @date 2021-10-30
|
||||||
|
* @since 1.5.0
|
||||||
|
*/
|
||||||
|
@Component(ScanCallbackGroupActor.BEAN_NAME)
|
||||||
|
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||||
|
@Slf4j
|
||||||
|
public class ScanCallbackGroupActor extends AbstractActor {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("retryTaskAccessProcessor")
|
||||||
|
private RetryTaskAccess<RetryTask> retryTaskAccessProcessor;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("bitSetIdempotentStrategyHandler")
|
||||||
|
private IdempotentStrategy<String, Integer> idempotentStrategy;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SystemProperties systemProperties;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("configAccessProcessor")
|
||||||
|
private ConfigAccess configAccess;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ClientNodeAllocateHandler clientNodeAllocateHandler;
|
||||||
|
|
||||||
|
public static final String BEAN_NAME = "ScanCallbackGroupActor";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Receive createReceive() {
|
||||||
|
return receiveBuilder().match(GroupConfig.class, config -> {
|
||||||
|
|
||||||
|
try {
|
||||||
|
doScan(config);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtils.error(log, "数据扫描器处理异常 [{}]", config, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}).build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扫描数据
|
||||||
|
*
|
||||||
|
* @param groupConfig
|
||||||
|
*/
|
||||||
|
private void doScan(GroupConfig groupConfig) {
|
||||||
|
|
||||||
|
LocalDateTime defLastAt = LocalDateTime.now().minusDays(systemProperties.getLastDays());
|
||||||
|
|
||||||
|
String groupName = groupConfig.getGroupName();
|
||||||
|
LocalDateTime lastAt = DispatchService.LAST_AT_CALL_BACK_MAP.getOrDefault(groupName, defLastAt);
|
||||||
|
|
||||||
|
// 扫描当前Group 待重试的数据
|
||||||
|
List<RetryTask> list = retryTaskAccessProcessor.listAvailableTasks(groupName, lastAt, systemProperties.getRetryPullPageSize(),
|
||||||
|
TaskTypeEnum.CALLBACK.getType());
|
||||||
|
|
||||||
|
if (!CollectionUtils.isEmpty(list)) {
|
||||||
|
|
||||||
|
DispatchService.LAST_AT_MAP.put(groupConfig.getGroupName(), list.get(list.size() - 1).getCreateDt());
|
||||||
|
|
||||||
|
|
||||||
|
for (RetryTask retryTask : list) {
|
||||||
|
|
||||||
|
retryCountIncrement(retryTask);
|
||||||
|
|
||||||
|
CallbackRetryContext<Result> retryContext = new CallbackRetryContext<>();
|
||||||
|
retryContext.setRetryTask(retryTask);
|
||||||
|
retryContext.setSceneBlacklist(configAccess.getBlacklist(groupName));
|
||||||
|
retryContext.setServerNode(clientNodeAllocateHandler.getServerNode(retryTask.getGroupName()));
|
||||||
|
|
||||||
|
RetryExecutor<Result> executor = RetryBuilder.<Result>newBuilder()
|
||||||
|
.withStopStrategy(StopStrategies.stopException())
|
||||||
|
.withStopStrategy(StopStrategies.stopResultStatus())
|
||||||
|
.withWaitStrategy(getWaitWaitStrategy())
|
||||||
|
.withFilterStrategy(FilterStrategies.delayLevelFilter())
|
||||||
|
.withFilterStrategy(FilterStrategies.bitSetIdempotentFilter(idempotentStrategy))
|
||||||
|
.withFilterStrategy(FilterStrategies.sceneBlackFilter())
|
||||||
|
.withFilterStrategy(FilterStrategies.checkAliveClientPodFilter())
|
||||||
|
.withFilterStrategy(FilterStrategies.rateLimiterFilter())
|
||||||
|
.withRetryContext(retryContext)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if (!executor.filter()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
productExecUnitActor(executor);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 数据为空则休眠5s
|
||||||
|
try {
|
||||||
|
Thread.sleep((DispatchService.PERIOD / 2) * 1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
DispatchService.LAST_AT_MAP.put(groupName, defLastAt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private WaitStrategy getWaitWaitStrategy() {
|
||||||
|
// 回调失败每15min重试一次
|
||||||
|
return WaitStrategies.WaitStrategyEnum.getWaitStrategy(WaitStrategies.WaitStrategyEnum.FIXED.getBackOff());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void retryCountIncrement(RetryTask retryTask) {
|
||||||
|
Integer retryCount = retryTask.getRetryCount();
|
||||||
|
retryTask.setRetryCount(++retryCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void productExecUnitActor(RetryExecutor<Result> retryExecutor) {
|
||||||
|
String groupIdHash = retryExecutor.getRetryContext().getRetryTask().getGroupName();
|
||||||
|
Long retryId = retryExecutor.getRetryContext().getRetryTask().getId();
|
||||||
|
idempotentStrategy.set(groupIdHash, retryId.intValue());
|
||||||
|
|
||||||
|
// 重试成功回调客户端
|
||||||
|
ActorRef actorRef = ActorGenerator.callbackRetryResultActor();
|
||||||
|
actorRef.tell(retryExecutor, actorRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,6 +2,7 @@ package com.aizuda.easy.retry.server.support.dispatch.actor.scan;
|
|||||||
|
|
||||||
import akka.actor.AbstractActor;
|
import akka.actor.AbstractActor;
|
||||||
import akka.actor.ActorRef;
|
import akka.actor.ActorRef;
|
||||||
|
import com.aizuda.easy.retry.common.core.enums.TaskTypeEnum;
|
||||||
import com.aizuda.easy.retry.server.support.retry.RetryExecutor;
|
import com.aizuda.easy.retry.server.support.retry.RetryExecutor;
|
||||||
import com.aizuda.easy.retry.server.support.strategy.FilterStrategies;
|
import com.aizuda.easy.retry.server.support.strategy.FilterStrategies;
|
||||||
import com.aizuda.easy.retry.server.support.strategy.StopStrategies;
|
import com.aizuda.easy.retry.server.support.strategy.StopStrategies;
|
||||||
@ -90,7 +91,7 @@ public class ScanGroupActor extends AbstractActor {
|
|||||||
LocalDateTime lastAt = DispatchService.LAST_AT_MAP.getOrDefault(groupName, defLastAt);
|
LocalDateTime lastAt = DispatchService.LAST_AT_MAP.getOrDefault(groupName, defLastAt);
|
||||||
|
|
||||||
// 扫描当前Group 待重试的数据
|
// 扫描当前Group 待重试的数据
|
||||||
List<RetryTask> list = retryTaskAccessProcessor.listAvailableTasks(groupName, lastAt, systemProperties.getRetryPullPageSize());
|
List<RetryTask> list = retryTaskAccessProcessor.listAvailableTasks(groupName, lastAt, systemProperties.getRetryPullPageSize(), TaskTypeEnum.RETRY.getType());
|
||||||
|
|
||||||
if (!CollectionUtils.isEmpty(list)) {
|
if (!CollectionUtils.isEmpty(list)) {
|
||||||
|
|
||||||
@ -108,7 +109,7 @@ public class ScanGroupActor extends AbstractActor {
|
|||||||
|
|
||||||
RetryExecutor<Result<DispatchRetryResultDTO>> executor = RetryBuilder.<Result<DispatchRetryResultDTO>>newBuilder()
|
RetryExecutor<Result<DispatchRetryResultDTO>> executor = RetryBuilder.<Result<DispatchRetryResultDTO>>newBuilder()
|
||||||
.withStopStrategy(StopStrategies.stopException())
|
.withStopStrategy(StopStrategies.stopException())
|
||||||
.withStopStrategy(StopStrategies.stopResultStatus())
|
.withStopStrategy(StopStrategies.stopResultStatusCode())
|
||||||
.withWaitStrategy(getWaitWaitStrategy(groupName, retryTask.getSceneName()))
|
.withWaitStrategy(getWaitWaitStrategy(groupName, retryTask.getSceneName()))
|
||||||
.withFilterStrategy(FilterStrategies.delayLevelFilter())
|
.withFilterStrategy(FilterStrategies.delayLevelFilter())
|
||||||
.withFilterStrategy(FilterStrategies.bitSetIdempotentFilter(idempotentStrategy))
|
.withFilterStrategy(FilterStrategies.bitSetIdempotentFilter(idempotentStrategy))
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.aizuda.easy.retry.server.support.handler;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import com.aizuda.easy.retry.common.core.constant.SystemConstants;
|
||||||
|
import com.aizuda.easy.retry.common.core.enums.RetryStatusEnum;
|
||||||
|
import com.aizuda.easy.retry.common.core.enums.TaskTypeEnum;
|
||||||
|
import com.aizuda.easy.retry.server.exception.EasyRetryServerException;
|
||||||
|
import com.aizuda.easy.retry.server.persistence.mybatis.po.RetryTask;
|
||||||
|
import com.aizuda.easy.retry.server.persistence.support.RetryTaskAccess;
|
||||||
|
import com.aizuda.easy.retry.server.service.convert.RetryTaskConverter;
|
||||||
|
import com.aizuda.easy.retry.server.support.strategy.WaitStrategies;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author www.byteblogs.com
|
||||||
|
* @date 2023-06-04
|
||||||
|
* @since 1.5.0
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class CallbackRetryTaskHandler {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("retryTaskAccessProcessor")
|
||||||
|
private RetryTaskAccess<RetryTask> retryTaskAccess;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void create(RetryTask retryTask) {
|
||||||
|
RetryTask callbackRetryTask = RetryTaskConverter.INSTANCE.toRetryTask(retryTask);
|
||||||
|
|
||||||
|
callbackRetryTask.setTaskType(TaskTypeEnum.CALLBACK.getType());
|
||||||
|
retryTask.setUniqueId(SystemConstants.CALL_BACK.CB_ + retryTask.getUniqueId());
|
||||||
|
retryTask.setRetryStatus(RetryStatusEnum.RUNNING.getStatus());
|
||||||
|
retryTask.setRetryCount(0);
|
||||||
|
retryTask.setCreateDt(LocalDateTime.now());
|
||||||
|
retryTask.setUpdateDt(LocalDateTime.now());
|
||||||
|
|
||||||
|
retryTask.setNextTriggerAt(WaitStrategies.randomWait(1, TimeUnit.SECONDS, 60, TimeUnit.SECONDS).computeRetryTime(null));
|
||||||
|
|
||||||
|
Assert.isTrue(1 == retryTaskAccess.saveRetryTask(callbackRetryTask), () -> new EasyRetryServerException("failed to report data"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -85,9 +85,7 @@ public class FilterStrategies {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean filter(RetryContext retryContext) {
|
public boolean filter(RetryContext retryContext) {
|
||||||
MaxAttemptsPersistenceRetryContext context = (MaxAttemptsPersistenceRetryContext) retryContext;
|
LocalDateTime nextTriggerAt = retryContext.getRetryTask().getNextTriggerAt();
|
||||||
|
|
||||||
LocalDateTime nextTriggerAt = context.getRetryTask().getNextTriggerAt();
|
|
||||||
return nextTriggerAt.isBefore(LocalDateTime.now());
|
return nextTriggerAt.isBefore(LocalDateTime.now());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,8 +129,7 @@ public class FilterStrategies {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean filter(RetryContext retryContext) {
|
public boolean filter(RetryContext retryContext) {
|
||||||
MaxAttemptsPersistenceRetryContext context = (MaxAttemptsPersistenceRetryContext) retryContext;
|
return !retryContext.getSceneBlacklist().contains(retryContext.getRetryTask().getSceneName());
|
||||||
return !context.getSceneBlacklist().contains(retryContext.getRetryTask().getSceneName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -148,8 +145,7 @@ public class FilterStrategies {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean filter(RetryContext retryContext) {
|
public boolean filter(RetryContext retryContext) {
|
||||||
MaxAttemptsPersistenceRetryContext context = (MaxAttemptsPersistenceRetryContext) retryContext;
|
ServerNode serverNode = retryContext.getServerNode();
|
||||||
ServerNode serverNode = context.getServerNode();
|
|
||||||
|
|
||||||
if (Objects.isNull(serverNode)) {
|
if (Objects.isNull(serverNode)) {
|
||||||
return false;
|
return false;
|
||||||
@ -173,8 +169,7 @@ public class FilterStrategies {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean filter(RetryContext retryContext) {
|
public boolean filter(RetryContext retryContext) {
|
||||||
MaxAttemptsPersistenceRetryContext context = (MaxAttemptsPersistenceRetryContext) retryContext;
|
ServerNode serverNode = retryContext.getServerNode();
|
||||||
ServerNode serverNode = context.getServerNode();
|
|
||||||
|
|
||||||
RateLimiter rateLimiter = CacheGroupRateLimiter.getRateLimiterByKey(serverNode.getHostId());
|
RateLimiter rateLimiter = CacheGroupRateLimiter.getRateLimiterByKey(serverNode.getHostId());
|
||||||
if (Objects.nonNull(rateLimiter) && !rateLimiter.tryAcquire(100, TimeUnit.MILLISECONDS)) {
|
if (Objects.nonNull(rateLimiter) && !rateLimiter.tryAcquire(100, TimeUnit.MILLISECONDS)) {
|
||||||
|
@ -31,14 +31,23 @@ public class StopStrategies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据客户端返回结果判断是否终止重试
|
* 根据客户端返回状态判断是否终止重试
|
||||||
*
|
*
|
||||||
* @return {@link ResultStatusStopStrategy} 重试结果停止策略
|
* @return {@link ResultStatusCodeStopStrategy} 重试结果停止策略
|
||||||
*/
|
*/
|
||||||
public static StopStrategy stopResultStatus() {
|
public static StopStrategy stopResultStatus() {
|
||||||
return new ResultStatusStopStrategy();
|
return new ResultStatusStopStrategy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据客户端返回结果对象的状态码判断是否终止重试
|
||||||
|
*
|
||||||
|
* @return {@link ResultStatusCodeStopStrategy} 重试结果停止策略
|
||||||
|
*/
|
||||||
|
public static StopStrategy stopResultStatusCode() {
|
||||||
|
return new ResultStatusCodeStopStrategy();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调用客户端发生异常触发停止策略
|
* 调用客户端发生异常触发停止策略
|
||||||
*/
|
*/
|
||||||
@ -61,20 +70,47 @@ public class StopStrategies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据客户端返回结果集判断是否应该停止
|
* 根据客户端返回的状态码判断是否应该停止
|
||||||
*
|
* <p>
|
||||||
* 1、{@link Result#getStatus()} 不为1 则继续重试
|
* 1、{@link Result#getStatus()} 不为1 则继续重试
|
||||||
* 2、根据{@link Result#getData()}中的statusCode判断是否停止
|
|
||||||
*/
|
*/
|
||||||
private static final class ResultStatusStopStrategy implements StopStrategy {
|
private static final class ResultStatusStopStrategy implements StopStrategy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldStop(RetryContext retryContext) {
|
public boolean shouldStop(RetryContext retryContext) {
|
||||||
|
|
||||||
MaxAttemptsPersistenceRetryContext<Result<DispatchRetryResultDTO>> context =
|
Result response = (Result) retryContext.getCallResult();
|
||||||
(MaxAttemptsPersistenceRetryContext<Result<DispatchRetryResultDTO>>) retryContext;
|
|
||||||
|
|
||||||
Result<DispatchRetryResultDTO> response = context.getCallResult();
|
if (Objects.isNull(response) || StatusEnum.YES.getStatus() != response.getStatus()) {
|
||||||
|
return Boolean.FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Boolean.TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(RetryContext retryContext) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int order() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据客户端返回结果集判断是否应该停止
|
||||||
|
* <p>
|
||||||
|
* 1、{@link Result#getStatus()} 不为1 则继续重试
|
||||||
|
* 2、根据{@link Result#getData()}中的statusCode判断是否停止
|
||||||
|
*/
|
||||||
|
private static final class ResultStatusCodeStopStrategy implements StopStrategy {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldStop(RetryContext retryContext) {
|
||||||
|
|
||||||
|
Result<DispatchRetryResultDTO> response = (Result<DispatchRetryResultDTO>) retryContext.getCallResult();
|
||||||
|
|
||||||
if (Objects.isNull(response) || StatusEnum.YES.getStatus() != response.getStatus()) {
|
if (Objects.isNull(response) || StatusEnum.YES.getStatus() != response.getStatus()) {
|
||||||
return Boolean.FALSE;
|
return Boolean.FALSE;
|
||||||
@ -97,7 +133,7 @@ public class StopStrategies {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int order() {
|
public int order() {
|
||||||
return 2;
|
return 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.aizuda.easy.retry.server.support.strategy;
|
package com.aizuda.easy.retry.server.support.strategy;
|
||||||
|
|
||||||
|
import com.aizuda.easy.retry.common.core.constant.SystemConstants;
|
||||||
|
import com.aizuda.easy.retry.common.core.enums.TaskTypeEnum;
|
||||||
import com.aizuda.easy.retry.server.exception.EasyRetryServerException;
|
import com.aizuda.easy.retry.server.exception.EasyRetryServerException;
|
||||||
import com.aizuda.easy.retry.server.persistence.mybatis.po.RetryTask;
|
import com.aizuda.easy.retry.server.persistence.mybatis.po.RetryTask;
|
||||||
import com.aizuda.easy.retry.server.persistence.mybatis.po.SceneConfig;
|
import com.aizuda.easy.retry.server.persistence.mybatis.po.SceneConfig;
|
||||||
@ -145,8 +147,7 @@ public class WaitStrategies {
|
|||||||
private static final class DelayLevelWaitStrategy implements WaitStrategy {
|
private static final class DelayLevelWaitStrategy implements WaitStrategy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LocalDateTime computeRetryTime(RetryContext retryContext) {
|
public LocalDateTime computeRetryTime(RetryContext context) {
|
||||||
MaxAttemptsPersistenceRetryContext context = (MaxAttemptsPersistenceRetryContext) retryContext;
|
|
||||||
RetryTask retryTask = context.getRetryTask();
|
RetryTask retryTask = context.getRetryTask();
|
||||||
DelayLevelEnum levelEnum = DelayLevelEnum.getDelayLevelByLevel(retryTask.getRetryCount());
|
DelayLevelEnum levelEnum = DelayLevelEnum.getDelayLevelByLevel(retryTask.getRetryCount());
|
||||||
return retryTask.getNextTriggerAt().plus(levelEnum.getTime(), levelEnum.getUnit());
|
return retryTask.getNextTriggerAt().plus(levelEnum.getTime(), levelEnum.getUnit());
|
||||||
@ -160,13 +161,20 @@ public class WaitStrategies {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LocalDateTime computeRetryTime(RetryContext retryContext) {
|
public LocalDateTime computeRetryTime(RetryContext retryContext) {
|
||||||
MaxAttemptsPersistenceRetryContext context = (MaxAttemptsPersistenceRetryContext) retryContext;
|
RetryTask retryTask = retryContext.getRetryTask();
|
||||||
RetryTask retryTask = context.getRetryTask();
|
int triggerInterval;
|
||||||
ConfigAccess configAccess = SpringContext.CONTEXT.getBean("configAccessProcessor", ConfigAccess.class);
|
if (TaskTypeEnum.CALLBACK.getType().equals(retryTask.getTaskType())) {
|
||||||
|
// 回调失败的默认15分钟执行一次重试
|
||||||
|
triggerInterval = SystemConstants.CALL_BACK.TRIGGER_INTERVAL;
|
||||||
|
} else {
|
||||||
|
ConfigAccess configAccess = SpringContext.CONTEXT.getBean("configAccessProcessor", ConfigAccess.class);
|
||||||
|
SceneConfig sceneConfig =
|
||||||
|
configAccess.getSceneConfigByGroupNameAndSceneName(retryTask.getGroupName(), retryTask.getSceneName());
|
||||||
|
triggerInterval = Integer.parseInt(sceneConfig.getTriggerInterval());
|
||||||
|
}
|
||||||
|
|
||||||
SceneConfig sceneConfig =
|
|
||||||
configAccess.getSceneConfigByGroupNameAndSceneName(retryTask.getGroupName(), retryTask.getSceneName());
|
return retryTask.getNextTriggerAt().plusSeconds(triggerInterval);
|
||||||
return retryTask.getNextTriggerAt().plusSeconds(Integer.parseInt(sceneConfig.getTriggerInterval()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,8 +184,7 @@ public class WaitStrategies {
|
|||||||
private static final class CronWaitStrategy implements WaitStrategy {
|
private static final class CronWaitStrategy implements WaitStrategy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LocalDateTime computeRetryTime(RetryContext retryContext) {
|
public LocalDateTime computeRetryTime(RetryContext context) {
|
||||||
MaxAttemptsPersistenceRetryContext context = (MaxAttemptsPersistenceRetryContext) retryContext;
|
|
||||||
RetryTask retryTask = context.getRetryTask();
|
RetryTask retryTask = context.getRetryTask();
|
||||||
|
|
||||||
ConfigAccess configAccess = SpringContext.CONTEXT.getBean(ConfigAccess.class);
|
ConfigAccess configAccess = SpringContext.CONTEXT.getBean(ConfigAccess.class);
|
||||||
@ -185,7 +192,7 @@ public class WaitStrategies {
|
|||||||
SceneConfig sceneConfig =
|
SceneConfig sceneConfig =
|
||||||
configAccess.getSceneConfigByGroupNameAndSceneName(retryTask.getGroupName(), retryTask.getSceneName());
|
configAccess.getSceneConfigByGroupNameAndSceneName(retryTask.getGroupName(), retryTask.getSceneName());
|
||||||
|
|
||||||
Date nextValidTime = null;
|
Date nextValidTime;
|
||||||
try {
|
try {
|
||||||
ZonedDateTime zdt = retryTask.getNextTriggerAt().atZone(ZoneOffset.ofHours(8));
|
ZonedDateTime zdt = retryTask.getNextTriggerAt().atZone(ZoneOffset.ofHours(8));
|
||||||
nextValidTime = new CronExpression(sceneConfig.getTriggerInterval()).getNextValidTimeAfter(Date.from(zdt.toInstant()));
|
nextValidTime = new CronExpression(sceneConfig.getTriggerInterval()).getNextValidTimeAfter(Date.from(zdt.toInstant()));
|
||||||
|
@ -11,10 +11,11 @@
|
|||||||
<result column="executor_name" jdbcType="VARCHAR" property="executorName" />
|
<result column="executor_name" jdbcType="VARCHAR" property="executorName" />
|
||||||
<result column="args_str" jdbcType="VARCHAR" property="argsStr" />
|
<result column="args_str" jdbcType="VARCHAR" property="argsStr" />
|
||||||
<result column="ext_attrs" jdbcType="VARCHAR" property="extAttrs" />
|
<result column="ext_attrs" jdbcType="VARCHAR" property="extAttrs" />
|
||||||
|
<result column="task_type" jdbcType="TINYINT" property="taskType"/>
|
||||||
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt" />
|
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, unique_id, group_name, scene_name, idempotent_id, biz_no, executor_name, args_str, ext_attrs, create_dt
|
id, unique_id, group_name, scene_name, idempotent_id, biz_no, executor_name, args_str, ext_attrs, create_dt, task_type
|
||||||
</sql>
|
</sql>
|
||||||
<insert id="insertBatch">
|
<insert id="insertBatch">
|
||||||
insert into retry_dead_letter_${partition} (id, unique_id, group_name, scene_name,
|
insert into retry_dead_letter_${partition} (id, unique_id, group_name, scene_name,
|
||||||
|
@ -12,12 +12,13 @@
|
|||||||
<result column="args_str" jdbcType="VARCHAR" property="argsStr"/>
|
<result column="args_str" jdbcType="VARCHAR" property="argsStr"/>
|
||||||
<result column="ext_attrs" jdbcType="VARCHAR" property="extAttrs"/>
|
<result column="ext_attrs" jdbcType="VARCHAR" property="extAttrs"/>
|
||||||
<result column="retry_status" jdbcType="TINYINT" property="retryStatus"/>
|
<result column="retry_status" jdbcType="TINYINT" property="retryStatus"/>
|
||||||
|
<result column="task_type" jdbcType="TINYINT" property="taskType"/>
|
||||||
<result column="error_message" jdbcType="VARCHAR" property="errorMessage"/>
|
<result column="error_message" jdbcType="VARCHAR" property="errorMessage"/>
|
||||||
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt"/>
|
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, unique_id, group_name, scene_name, idempotent_id, biz_no, executor_name, args_str, ext_attrs, retry_status, error_message,
|
id, unique_id, group_name, scene_name, idempotent_id, biz_no, executor_name, args_str, ext_attrs, retry_status, error_message,
|
||||||
create_dt
|
create_dt, task_type
|
||||||
</sql>
|
</sql>
|
||||||
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
|
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
|
||||||
select
|
select
|
||||||
|
@ -14,12 +14,13 @@
|
|||||||
<result column="next_trigger_at" jdbcType="TIMESTAMP" property="nextTriggerAt" />
|
<result column="next_trigger_at" jdbcType="TIMESTAMP" property="nextTriggerAt" />
|
||||||
<result column="retry_count" jdbcType="TINYINT" property="retryCount" />
|
<result column="retry_count" jdbcType="TINYINT" property="retryCount" />
|
||||||
<result column="retry_status" jdbcType="TINYINT" property="retryStatus" />
|
<result column="retry_status" jdbcType="TINYINT" property="retryStatus" />
|
||||||
|
<result column="task_type" jdbcType="TINYINT" property="taskType"/>
|
||||||
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt" />
|
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt" />
|
||||||
<result column="update_dt" jdbcType="TIMESTAMP" property="updateDt" />
|
<result column="update_dt" jdbcType="TIMESTAMP" property="updateDt" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, unique_id, group_name, scene_name, idempotent_id, biz_no, executor_name, args_str, ext_attrs, next_trigger_at, retry_count, retry_status,
|
id, unique_id, group_name, scene_name, idempotent_id, biz_no, executor_name, args_str, ext_attrs, next_trigger_at, retry_count, retry_status,
|
||||||
create_dt, update_dt
|
create_dt, update_dt, task_type
|
||||||
</sql>
|
</sql>
|
||||||
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
|
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
|
||||||
select
|
select
|
||||||
|
Loading…
Reference in New Issue
Block a user