任务调度设计

目录

一、页面任务配置DAG图

二、实现方式1

1、根据DAG的顺序执行任务设计(java实现)

2、任务定时调度起来

3、多台机器怎么保证同一个任务只执行一次?

4、某台服务器要是挂了怎么办?

5、如何判断服务器挂掉了?

三、实现方式2

1、任务定时调度起来

2、如何保证定时任务只在一台机器调度?

3、机器挂了怎么办?

4、定时任务还在跑,失效时间就过了怎么办?

5、如何判定任务有没有跑完?


一、页面任务配置DAG图

任务调度设计_第1张图片

二、实现方式1

1、根据DAG的顺序执行任务设计(java实现)

(1)将ABCDEFG任务放入一个List 

List taskList = new ArrayList();

(2)根据任务之间的依赖关系构建一个Map>数组,key=当前任务,value=当前任务的上游节点

Map> map = new HashMap();

任务调度设计_第2张图片

(3)循环遍历taskList,判断当前节点有没有上游节点,如果没有上游节点则将任务跑起来,有上游节点则判断上游节点是否已经跑过,如果上游都已经跑过,则将当前节点跑起来,否则跳过当前循环

import lombok.Data;

@Data
public class Task {
    private String name;
    private int state; //任务状态,0:未执行,1:已执行

    public Task(String name, int state) {
        this.name = name;
        this.state = state;
    }

    public boolean execute() {
        state = 1;
        System.out.println("任务[" + name + "]的执行逻辑");
        return true;
    }
}
import lombok.Data;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

@Data
public class Dag {
    private Set tasks;
    private Map> map;

    public Dag() {
        this.tasks = new HashSet();
        this.map = new HashMap();
    }

    public void addEdge(Task task, Task preTaks) {
        if (!tasks.contains(task) || !tasks.contains(preTaks)) {
            throw new RuntimeException("任务不存在");
        }
        Set preSet = map.get(task);
        if (preSet == null) {
            preSet = new HashSet();
            map.put(task, preSet);
        }
        if (preSet.contains(preTaks)) {
            throw new RuntimeException("上游节点不存在");
        }
        preSet.add(preTaks);
    }

    public void addTask(Task task) {
        if (tasks.contains(task)) {
            throw new RuntimeException();
        }
        tasks.add(task);
    }
}

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class TaskScheduler {
    public void schedule(Dag digraph) {
        while (true) {
            List todo = new ArrayList();
            for (Task task : digraph.getTasks()) {
                if (task.getState() == 0) {
                    Set prevs = digraph.getMap().get(task);
                    if (prevs != null && !prevs.isEmpty()) {
                        boolean toAdd = true;
                        for (Task preTask : prevs) {
                            if (preTask.getState() == 0) {
                                toAdd = false;
                                break;
                            }
                        }
                        if (toAdd) {
                            todo.add(task);
                        }
                    } else {
                        todo.add(task);
                    }
                }
            }
            if (!todo.isEmpty()) {
                for (Task task : todo) {
                    if (!task.execute()) {
                        throw new RuntimeException();
                    }
                }
            } else {
                break;
            }
        }
    }

    public static void main(String[] args) {
        Dag dag = new Dag();
        Task a = new Task( "A", 0);
        Task b = new Task( "B", 0);
        Task c = new Task( "C", 0);
        Task d = new Task( "D", 0);
        Task e = new Task( "E", 0);
        Task f = new Task( "F", 0);
        Task g = new Task( "G", 0);
        dag.addTask(a);
        dag.addTask(b);
        dag.addTask(c);
        dag.addTask(d);
        dag.addTask(e);
        dag.addTask(f);
        dag.addTask(g);
        dag.addEdge(c, b);
        dag.addEdge(d, a);
        dag.addEdge(d, c);
        dag.addEdge(e, d);
        dag.addEdge(f, d);
        dag.addEdge(g, f);
        TaskScheduler scheduler = new TaskScheduler();
        scheduler.schedule(dag);
    }
}

任务调度设计_第3张图片

2、任务定时调度起来

        利用quartz框架

3、多台机器怎么保证同一个任务只执行一次?

        有一张任务表,每个任务生成都会在表里插入一条记录,有个host_name字段,任务生成后,对任务设置host_name,固定任务在某一台机器跑

4、某台服务器要是挂了怎么办?

        执行任务只执行数据库中任务状态为待执行的任务,获取host_name,心跳判断机器是否挂了,如果挂了则修改任务的host_name,

5、如何判断服务器挂掉了?

        另起一个任务,轮询获取数据库中记录的机器,当前时间和数据库里记录的时间对比,超过一分钟则判断该机器挂掉

三、实现方式2

1、任务定时调度起来

(1)创建一张任务实例表(任务和任务实例表的关系是一对多关系,一个任务可创建多个实例,如:配置了一个天任务,每天任务都会跑起来,那就是每天一个实例)

(2)根据DAG关系,00:00的时候把前一天所有的任务都根据依赖关系把实例创建好

(3)开启一个定时任务,10秒钟轮询一次,获取当前未执行的任务,判断是否可以执行,如果可以执行则执行,且修改任务状态。

2、如何保证定时任务只在一台机器调度?

redis分布式锁,将某台机器的ip作为值放入redis,任务跑的时候获取redis中的ip和当前机器ip进行对比,两者相等则在当前机器将任务跑起来。

3、机器挂了怎么办?

redis中获取机器ip的key设置失效时间

4、定时任务还在跑,失效时间就过了怎么办?

另启一个任务去轮询判断任务与有没有跑完,如果超过一定时间还没跑完,将redis中的失效时间延长。

5、如何判定任务有没有跑完?

任务跑完或者出现异常在redis中设置一个值,定时任务轮询该值有无来判断任务跑完了。

防止异常现象导致锁一直续时,设置可以预估锁释放时间,超过多少时间后就不续时了。如:本来正常一个任务跑10分钟就结束了,但是因为意外的原因导致一小时过去了,redis中都查不到值表明这个任务跑挂了或者已经结束了,那就设置1小时,超过这个时间就不续时了

备注:4、5的解决的问题在上述设计中其实并不需要考虑到,上述提到的任务实例生成实际就跑一次,只有在定时任务是轮询执行的时候才需要考虑。另,如果遇到4、5的场景,也可以用Redission来代替解决

小时、分钟、天、周、月级别的任务依赖怎么设计,待补充……

你可能感兴趣的:(项目设计,项目设计)