ecodeclub / ecron

大规模分布式任务调度系统(学习版)
Apache License 2.0
78 stars 21 forks source link

主动探查停机-恢复解决方案 #27

Open flycash opened 2 months ago

flycash commented 2 months ago

在我们的主动探查机制里面,有一个问题: 假设说我当次任务在节点 A 上被调度,理论上来说,它也可以应该在 A 上探查。但是如果此时 A 节点宕机了,那么后续即使 A 节点恢复了,它也无法继续探查。因为目前我们的探查是基于内存实现的,虽然有执行记录,但是 A 节点恢复之后无法从执行记录里面找到哪些是自己需要继续探查的。

我们可以进一步借助抢占机制来解决这个问题。

在我们抢占的时候,有一个条件是如果一个任务已经被抢占了,但是更新时间超过了最大续约时间。换句话来说,没人给它续约。这个时候我们就有道理认为,这个节点之前抢占了这个任务,但是并没有正常释放。

这个时候,在找到这样一个任务之后,就要先去看一眼这个任务最近的一次执行记录,是否已经结束。如果没有结束,那么就要发起探查。而后根据结果来考虑:

junwense commented 2 months ago

你这个想法有点奇怪,那要还是要有getTasks的抽象,把任务都查出来,进行探查或者抢占,然后就比较尴尬了,可能其他节点也会查出这个任务来

flycash commented 2 months ago

不会的,因为你抢占只会有一个节点抢占成功。你可以理解为,是在已有抢占成功的基础上,看看非正常释放任务,上一次有咩有执行完毕

pojiang20 commented 1 month ago

目前main和dev都没办法跑起来,有能跑的分支吗?

yanleiwang commented 1 month ago

类似这样吗?

    if t.LastStatus == mysql.TaskStatusRunning {
        // 根据 Task.ID 获取 execute id
        execution, err := p.executionDAO.GetByTid(ctx, t.ID)
        if err != nil {
            return
        }
        // 再根据 eid 查询 上次执行情况
        ch := exec.Explore(ctx, execution.ID, t)
        select {
        case res, ok := <-ch:
            if !ok {
                return
            }
            switch res.Status {
            // 还在执行的任务
            case executor.StatusRunning:
                //TODO 只定时探查 不调度
                return
            default:
            }
        case <-ctx.Done():
            return
        }
    }
    // 正常调度 执行
flycash commented 1 month ago

是的。不过我们没有这个 LastStatus 的字段,理论上来说,我们抢占是先查询出来了 Task,而后再抢占,所以查询出来的状态本身就是 Running。抢占只是改了数据库的,但是已经查询出来的没改