本文主要介绍真实代码实现
序言
根据前面两篇文章的梳理
【性能优化】:探索系统瓶颈的根源(一)
【性能优化】:设计模式与技术方案解析(二)
我们已经知道了自动化跑批系统
的核心功能,今天就来真正的代码实现下。
代码实现
步骤状态
public enum CurrentStepStatus {
ABSENT(0, "步骤不存在"),
STOP(1, "步骤被终止了"),
SUCCESS(2, "步骤成功"),
RUNNING(3, "步骤在运行中"),
FAILED(4, "步骤失败了"),
NOSTART(5, "步骤未启动");
}
调度器模板类
/**
* @description:调度器抽象接口
*/
public abstract class DispatchStepHandler {
public final boolean handler() {
if (checkPreviousStepStatus()) {
String status = checkCurrentStepStatus();
if (Objects.isNull(status)) {
return false;
}
if (CurrentStepStatus.ABSENT.name().equals(status) || CurrentStepStatus.STOP.name().equals(status)) {
return false;
}
if (CurrentStepStatus.SUCCESS.name().equals(status) || CurrentStepStatus.RUNNING.name().equals(status)) {
//成功态或运行态,不会执行业务逻辑,跳过去
return true;
} else {
return businessOltp();
}
}
return false;
}
/**
* 检查前一个步骤的状态:只有前一个步骤执行成功后,才能执行当前步骤
* @return
*/
protected abstract boolean checkPreviousStepStatus();
/**
* 当前步骤业务处理
* @return
*/
protected abstract boolean businessOltp();
/**
* 在执行当前步骤业务逻辑前,先检查当前步骤的状态,步骤不存在或者是stop状态,则整个调度链停止运行
* @return
*/
public abstract String checkCurrentStepStatus();
}
核心抽象方法说明
- checkPreviousStepStatus 检查前一个步骤的状态,只有前一个步骤执行成功后,才能执行当前步骤;
- checkCurrentStepStatus 检查当前步骤状态,步骤不存在或者是停止状态,则整个调度链停止运行,步骤是成功或运行状态则跳过;
- businessOltp 当前步骤的核心业务逻辑。
步骤实现类
每个步骤都是一个业务实现类,去实现抽象的调度器模板接口
以 Step1Handler
为例
/**
* @description:步骤1:业务数据导入实现类
*/
@Service
@Slf4j
public class Step1Handler extends StepCommonService {
@Autowired
private DingService dingService;
/**
* 检查前一个步骤的状态:只有前一个步骤执行成功后,才能执行当前步骤
* @return
*/
@Override
protected boolean checkPreviousStepStatus() {
return true;
}
/**
* 在执行当前步骤业务逻辑前,先检查当前步骤的状态,步骤不存在或者是stop状态,则整个调度链停止运行
* @return
*/
@Override
public String checkCurrentStepStatus() {
return super.checkCurrentStepStatus("step1");
}
/**
* 当前步骤业务处理
* @return
*/
@Override
@DingMonitor(node = "step1", remark = "增量数据导入", input = true, output = true)
protected boolean businessOltp() {
try {
/**
* 核心业务逻辑
*/
return true;
} catch (Exception e) {
log.error("步骤一【增量数据导入】异常", e);
dingService.sendDingWarn("步骤一", "增量数据导入异常");
return false;
}
}
}
责任链类
@Component
@Slf4j
public class StepHandlerChain {
@Autowired
private List<DispatchStepHandler> stepHandlers;
@Autowired
private DispatchService dispatchServiceImpl;
private List<DispatchStepHandler> handlers = new ArrayList<>();
@PostConstruct
void init() {
for(DispatchStepHandler handler:stepHandlers){
handlers.add(handler);
}
}
/**
* 执行真实业务类方法
*/
public void execute() {
boolean allStatus = true;
for (DispatchStepHandler handler : handlers) {
boolean result = handler.handler();
if (!result) {
allStatus = false;
break;
}
}
if (allStatus) {
log.info("所有步骤执行成功,开始更新dispatch表状态");
/**
* 更新dispatch表
*/
} else {
log.info("存在失败的步骤,dispatch表状态不能更新");
}
}
}
入口类
@EncryptCommon
@DingMonitor(node = "step0", remark = "业务跑批")
@GetMapping("/dispatchChain")
public Object dispatchChain(){
log.info("开始执行责任链步骤");
try {
// 前置逻辑
stepHandlerChain.execute(); //调度链入口
} catch (Exception e) {
log.info("执行责任链步骤异常", e);
return Res.error("调度异常");
}
return Res.success();
}
总结
通过 3 篇文章,大概介绍了自动化跑批系统实现的历程,由于篇幅有限还有一些细节的点没有介绍,不过这也不是重点。
核心是我们碰到瓶颈点的时候怎么去思考问题,分析问题,然后去付诸行动。
真正的挑战在于,我们发现了问题,却选择了妥协和将就,而不是追求卓越和改进