SchedulerController、SchedulerService
考虑到Controler逻辑非常简单(不合理),此处将controller和service合并分析。
同样SchedulerController几乎没有什么逻辑,全都交给了SchedulerService层。这里只分析SchedulerService.insertSchedule,简单浏览代码后,可以发现它跟createProcessDefinition逻辑差不多:
- 校验当前用户是否拥有所属项目的权限
- 校验流程定义JSON是否合法。例如是否有环
- 构造Schedule对象插入数据库
- 设置HTTP返回结果
当然除了上面4点还查询、更新了ProcessDefinition,主要是将Schedule和ProcessDefinition进行关联。
MasterSchedulerThread
以上是MasterSchedulerThread类的概览图。
MasterSchedulerThread实现Runnable接口,很明显主要的逻辑应该在run方法内,而且根据经验以及前面的分析可以知道,这个方法内是一个“死”循环,且为了避免CPU飙升,会休眠一小段时间。
下面我们逐步展开、分析MasterSchedulerThread类
从上图简单分析,总结一下run的逻辑:
- 调用OSUtils.checkResource,检查当前资源(内存、CPU)。
- 资源超出阈值,则休眠1秒进入下一次循环。
- 检查zookeeper是否连接成功
- 获取一个InterProcessMutex锁(分布式的公平可重入互斥锁)。也就是只有一个master可以获取到这个锁
- 查询一个Command,不为null时进行后续逻辑。
- 休眠1秒,进入下一次循环
- 进入下一次循环之前,释放InterProcessMutex锁
在深入分析run之前,先简单分析一下 Stopper.isRunning() 的逻辑。
/**
* if the process closes, a signal is placed as true, and all threads get this flag to stop working
*/
public class Stopper {
private static volatile AtomicBoolean signal = new AtomicBoolean(false);
public static final boolean isStoped(){
return signal.get();
}
public static final boolean isRunning(){
return !signal.get();
}
public static final void stop(){
signal.getAndSet(true);
}
}
其逻辑非常简单,就是用一个原子布尔值,标志当前进程是否要退出。如果收到了退出信号,则signal为true,该进程内所有的线程都退出当前循环。
下面我们来分析查询到一个Command之后的逻辑:
if (command != null) {
logger.info(String.format("find one command: id: %d, type: %s", command.getId(),command.getCommandType().toString()));
try{
processInstance = processDao.handleCommand(logger, OSUtils.getHost(), this.masterExecThreadNum - activeCount, command);
if (processInstance != null) {
logger.info("start master exec thread , split DAG ...");
masterExecService.execute(new MasterExecThread(processInstance,processDao));
}
}catch (Exception e){
logger.error("scan command error ", e);
processDao.moveToErrorCommand(command, e.toString());
}
}
其实就是根据Command创建了一个ProcessInstance(流程实例),之前也分析过,流程定义是由Scheduler自动创建的,而Quartz已经根据Schedule信息创建了Command保存到了数据库。至此,流程定义与定时的关联逻辑就已经串起来了。
创建流程实例的时候传入了当前可用(masterExecThreadNum - activeCount)的线程数量,如果满足当前dag,则返回ProcessInstance,否则返回null。
ProcessInstance最终交由MasterExecThread去执行。
至此MasterSchedulerThread类的主要逻辑如下:
- 调用OSUtils.checkResource,检查当前资源(内存、CPU)。
- 资源超出阈值,则休眠1秒进入下一次循环。
- 检查zookeeper是否连接成功
- 获取一个InterProcessMutex锁(分布式的公平可重入互斥锁)。也就是只有一个master可以获取到这个锁
- 查询一个Command,如果当前线程数够用,则创建一个流程实例(ProcessInstance),交给MasterExecThread线程处理。
- 休眠1秒,进入下一次循环
- 进入下一次循环之前,释放InterProcessMutex锁