All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetlinks.rule.engine.defaults.LocalScheduler Maven / Gradle / Ivy

The newest version!
package org.jetlinks.rule.engine.defaults;

import lombok.Getter;
import lombok.Setter;
import org.jetlinks.core.trace.FluxTracer;
import org.jetlinks.rule.engine.api.RuleConstants;
import org.jetlinks.rule.engine.api.scheduler.ScheduleJob;
import org.jetlinks.rule.engine.api.scheduler.Scheduler;
import org.jetlinks.rule.engine.api.task.Task;
import org.jetlinks.rule.engine.api.worker.Worker;
import org.jetlinks.rule.engine.api.worker.WorkerSelector;
import reactor.core.Disposable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Function;

public class LocalScheduler implements Scheduler, Disposable {

    //调度器ID
    @Getter
    private final String id;

    @Setter
    private WorkerSelector workerSelector = defaultSelector;

    //工作节点选择器,用来选择合适的节点来执行任务
    final static WorkerSelector defaultSelector = (workers1, rule) -> workers1.take(1);

    private final Map workers = new ConcurrentHashMap<>();

    private final Map>> executors = new ConcurrentHashMap<>();

    private final Map tasks = new ConcurrentHashMap<>();

    public LocalScheduler(String id) {
        this.id = id;
    }

    /**
     * @return 全部工作器
     */
    @Override
    public Flux getWorkers() {
        return Flux.fromIterable(workers.values());
    }

    /**
     * 获取指定ID的工作器
     *
     * @param workerId ID
     * @return 工作器
     */
    @Override
    public Mono getWorker(String workerId) {

        return Mono.justOrEmpty(workers.get(workerId));
    }

    /**
     * 当前调度器是否可以调度此任务
     *
     * @param job 任务信息
     * @return 是否可以调度
     */
    @Override
    public Mono canSchedule(ScheduleJob job) {
        return findWorker(job.getExecutor(), job)
            .hasElements();
    }

    protected Flux findWorker(String executor, ScheduleJob schedulingRule) {
        return workerSelector
            .select(Flux.fromIterable(workers.values())
                        .filterWhen(exe -> exe
                            .getSupportExecutors()
                            .map(list -> list.contains(executor))
                            .defaultIfEmpty(false)), schedulingRule);
    }

    @Override
    public Flux schedule(ScheduleJob job) {

        return Flux
            .fromIterable(getExecutor(job.getInstanceId(), job.getNodeId()))
            .flatMap(task -> {
                //停止旧任务
                removeTask(task);
                return task.shutdown();
            })
            .thenMany(createExecutor(job))
            .as(RuleConstants.Trace.traceFlux(job, "schedule"));
    }

    @Override
    public Mono shutdown(String instanceId) {
        return getSchedulingTask(instanceId)
            .doOnNext(task -> tasks.remove(task.getId()))
            .concatMapDelayError(Task::shutdown)
            .doAfterTerminate(() -> clearExecutor(instanceId))
            .then();
    }

    @Override
    public Mono shutdownTask(String taskId) {
        Task task = removeTask(taskId);
        if (null != task) {
            return task.shutdown().then();
        }
        return Mono.empty();
    }

    private Flux createExecutor(ScheduleJob job) {
        return findWorker(job.getExecutor(), job)
            .switchIfEmpty(Mono.error(() -> new UnsupportedOperationException("unsupported executor:" + job.getExecutor())))
            .flatMap(worker -> worker.createTask(id, job))
            .doOnNext(this::addTask);
    }

    private void addTask(Task task) {
        Task old = tasks.put(task.getId(), task);
        if (old != null && task != old) {
            old.shutdown().subscribe();
        }
        getExecutor(task.getJob().getInstanceId(), task.getJob().getNodeId()).add(task);
    }

    private Task removeTask(String taskId) {
        Task task = tasks.get(taskId);
        if (task != null) {
            removeTask(task);
        }
        return task;
    }

    private void removeTask(Task task) {
        tasks.remove(task.getId());
        getExecutor(task.getJob().getInstanceId(), task.getJob().getNodeId()).remove(task);
    }

    @Override
    public Flux getSchedulingTask(String instanceId) {
        return Flux.fromIterable(getExecutor(instanceId).values())
                   .flatMapIterable(Function.identity());
    }

    @Override
    public Mono getTask(String taskId) {
        return Mono.justOrEmpty(tasks.get(taskId));
    }

    @Override
    public Flux getSchedulingTasks() {
        return Flux.fromIterable(executors.values())
                   .flatMapIterable(Map::values)
                   .flatMapIterable(Function.identity());
    }

    @Override
    public Mono totalTask() {
        return getSchedulingTasks().count();
    }

    private List getExecutor(String instanceId, String nodeId) {
        return getExecutor(instanceId).computeIfAbsent(nodeId, ignore -> new CopyOnWriteArrayList<>());
    }

    private void clearExecutor(String instanceId) {
        executors.remove(instanceId);
    }

    private Map> getExecutor(String instanceId) {
        return executors.computeIfAbsent(instanceId, ignore -> new ConcurrentHashMap<>());
    }

    public void addWorker(Worker worker) {
        this.workers.put(worker.getId(), worker);
    }

    @Override
    public void dispose() {
        for (Task value : tasks.values()) {
            value.shutdown().subscribe();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy