2021SC@SDUSC(dolphinscheduler- common3)

数据库与队列操作:任务实例的提交与状态跟踪
本文解析了如何通过processDao将任务实例提交到数据库并放入Zookeeper队列,详细介绍了`submitTask`和`submitTaskToQueue`方法的工作原理。重点在于MasterTaskExecThread中的任务管理和waitTaskQuit的逻辑循环。

接下来看看作业是如何提交的,也比较简单,就是调用了processDao.submitTask。

protected TaskInstance submit(){
    Integer commitRetryTimes = conf.getInt(Constants.MASTER_COMMIT_RETRY_TIMES,
            Constants.defaultMasterCommitRetryTimes);
    Integer commitRetryInterval = conf.getInt(Constants.MASTER_COMMIT_RETRY_INTERVAL,
            Constants.defaultMasterCommitRetryInterval);

    int retryTimes = 1;

    while (retryTimes <= commitRetryTimes){
        try {
            TaskInstance task = processDao.submitTask(taskInstance, processInstance);
            if(task != null){
                return task;
            }
            logger.error("task commit to mysql and queue failed , task has already retry {} times, please check the database", commitRetryTimes);
            Thread.sleep(commitRetryInterval);
        } catch (Exception e) {
            logger.error("task commit to mysql and queue failed : " + e.getMessage(),e);
        }
        retryTimes += 1;
    }
    return null;
}

根据前面的分析我们知道processDao就是跟数据库打交道的,暂时猜测这里就是把任务实例插入到了数据。

public TaskInstance submitTask(TaskInstance taskInstance, ProcessInstance processInstance){
    logger.info("start submit task : {}, instance id:{}, state: {}, ",
            taskInstance.getName(), processInstance.getId(), processInstance.getState() );
    processInstance = this.findProcessInstanceDetailById(processInstance.getId());
    //submit to mysql
    TaskInstance task= submitTaskInstanceToMysql(taskInstance, processInstance);
    if(task.isSubProcess() && !task.getState().typeIsFinished()){
        ProcessInstanceMap processInstanceMap = setProcessInstanceMap(processInstance, task);

        TaskNode taskNode = JSONUtils.parseObject(task.getTaskJson(), TaskNode.class);
        Map<String, String> subProcessParam = JSONUtils.toMap(taskNode.getParams());
        Integer defineId = Integer.parseInt(subProcessParam.get(Constants.CMDPARAM_SUB_PROCESS_DEFINE_ID));
        createSubWorkProcessCommand(processInstance, processInstanceMap, defineId, task);
    }else if(!task.getState().typeIsFinished()){
        //submit to task queue
        task.setProcessInstancePriority(processInstance.getProcessInstancePriority());
        submitTaskToQueue(task);
    }
    logger.info("submit task :{} state:{} complete, instance id:{} state: {}  ",
            taskInstance.getName(), task.getState(), processInstance.getId(), processInstance.getState());
    return task;

这段代码优点复杂,但只需要看其主干逻辑就好了。也就是调用submitTaskInstanceToMysql把任务实例插入到数据库,然后调用submitTaskToQueue(目前还看不出插入到了哪里)。

submitTaskInstanceToMysql不再贴源码分析,与函数名差不多,就是把instance插入到数据库。

submitTaskToQueue主干逻辑就是把taskInstance添加到了TaskQueue。

public Boolean submitTaskToQueue(TaskInstance taskInstance) {

    try{
        // task cannot submit when running
        if(taskInstance.getState() == ExecutionStatus.RUNNING_EXEUTION){
            logger.info(String.format("submit to task queue, but task [%s] state already be running. ", taskInstance.getName()));
            return true;
        }
        if(checkTaskExistsInTaskQueue(taskInstance)){
            logger.info(String.format("submit to task queue, but task [%s] already exists in the queue.", taskInstance.getName()));
            return true;
        }
        logger.info("task ready to queue: {}" , taskInstance);
        taskQueue.add(DOLPHINSCHEDULER_TASKS_QUEUE, taskZkInfo(taskInstance));
        logger.info(String.format("master insert into queue success, task : %s", taskInstance.getName()) );
        return true;
    }catch (Exception e){
        logger.error("submit task to queue Exception: ", e);
        logger.error("task queue error : %s", JSONUtils.toJson(taskInstance));
        return false;

    }
}

taskQueue是TaskQueueFactory.getTaskQueueInstance()创建的。

protected ITaskQueue taskQueue = TaskQueueFactory.getTaskQueueInstance();

getTaskQueueInstance其实就是调用了TaskQueueZkImpl.getInstance(),这应该是一个遗留接口。估计设计初期是想根据配置创建不同的任务队列,比如redis或者其他,目前只支持zookeeper。

public static ITaskQueue getTaskQueueInstance() {
  String queueImplValue = CommonUtils.getQueueImplValue();
  if (StringUtils.isNotBlank(queueImplValue)) {
      logger.info("task queue impl use zookeeper ");
      return TaskQueueZkImpl.getInstance();
  }else{
    logger.error("property dolphinscheduler.queue.impl can't be blank, system will exit ");
    System.exit(-1);
  }

  return null;
}

既然只支持zookeeper,这段代码是冗余的

这样来看submitTaskToQueue就是调用TaskQueueZkImpl.add方法,把任务实例插入到了zookeeper实现的队列中。

public void add(String key, String value) {
    try {
        String taskIdPath = getTasksPath(key) + Constants.SINGLE_SLASH + value;
        String result = getZkClient().create().withMode(CreateMode.PERSISTENT).forPath(taskIdPath, Bytes.toBytes(value));

        logger.info("add task : {} to tasks queue , result success",result);
    } catch (Exception e) {
        logger.error("add task to tasks queue exception",e);
    }

}

从上下文我们知道,这里的key就是tasks_queue;根据注释,value就是 ${processInstancePriority}${processInstanceId}${taskInstancePriority}_${taskId}_host1,host2...

这样来看,add就是在zk的tasks_queue父节点下创建子节点,子节点的data就是value的值。

submit的逻辑分析完毕,来继续分析submitWaitComplete的剩余主要逻辑:waitTaskQuit。

waitTaskQuit

 

waitTaskQuit代码比较多,先从整体来分析其逻辑:

  1. 通过taskInstance.id查询taskInstance。其实就是查询taskInstance的最新状态。
  2. 通过参数判断是否启用超时检查
  3. 一个while“死循环”。
  4. while中判断任务是否执行结束,是则退出
  5. 获取任务实例、流程实例最新状态
  6. 休眠1秒,进入下一次while循环

简单来说waitTaskQuit就是循环查看任务实例的状态,直至其成功。

MasterTaskExecThread的功能整体来看就是把任务实例信息插入到数据库,并放到zookeeper队列,然后循环等待任务实例的状态变成完成,并没有任何具体的执行逻辑。

Stopper.isRunning()作为一个全局变量,控制了N多的线程,每个线程都处于一个while“死循环”中。

### 2021 SC SDUSC IT相关信息 #### ByteToMessageDecoder解析 `ByteToMessageDecoder` 是Netty框架中的一个重要解码器类,用于处理字节流到消息对象的转换过程。此类实现了入站处理器接口,在接收到的数据被读取之后触发调用方法来执行具体的解码逻辑[^1]。 ```java public abstract class ByteToMessageDecoder extends ChannelInboundHandlerAdapter { protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception; } ``` 该类提供了一个抽象方法 `decode()` ,子类需实现此方法完成特定的应用层协议解析工作。当有新的数据到达时会自动调用这个函数来进行逐步解码操作直到所有可用输入都被消耗完毕为止。 #### 后端文件夹sdudoc-mbg分析 针对项目后端部分中名为 `sdudoc-mbg` 的模块进行了深入探讨。这部分主要涉及数据库映射生成工具MyBatis Generator (MBG),它能够自动生成持久化所需的Java实体类以及相应的DAO访问代码,大大提高了开发效率并减少了手工编写重复SQL语句的工作量[^2]。 #### 数据结构定义EVP_CIPHER_CTX 在OpenSSL库中存在一种称为 `EVP_CIPHER_CTX` 的数据类型,其实际是一个指向内部结构体指针类型的别名声明。这种上下文环境主要用于加密算法的操作过程中保存状态信息和其他必要的参数设置等[^3]: ```c typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX; ``` 上述代码片段展示了如何通过宏定义的方式创建一个新的类型名称以便于后续编程使用更加直观易懂。 #### Senta输入变量说明 Senta作为自然语言处理平台之一,在接收外部传入的数据时支持多种基础数值型张量形式作为模型训练样本集的一部分。具体来说就是允许用户指定维度大小不固定的矩阵或者向量,并且限定了所含元素仅能采用浮点数或整数两种基本类别以确保计算精度满足需求[^4]。 #### 组件特性描述 为了增强系统的灵活性和健壮性,某些组件设计上融入了几项重要的机制:日志记录能力使得开发者可以在运行期间获取详细的调试线索;配置管理则让用户可以根据实际情况调整行为模式而无需修改源代码本身;资源清理功能保证了即使发生异常也能安全地终止程序而不遗留未关闭的对象实例;最后循环利用策略有助于降低垃圾收集频率进而优化整体性能表现并缓解潜在内存压力问题[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值