TaskUtils.java 7.69 KB
package com.viontech.fanxing.task.utils;

import cn.hutool.core.collection.ListUtil;
import com.google.common.collect.ArrayListMultimap;
import com.viontech.fanxing.commons.constant.TaskStatus;
import com.viontech.fanxing.commons.exception.FanXingException;
import com.viontech.fanxing.commons.model.Task;
import com.viontech.fanxing.commons.model.TaskExample;
import com.viontech.fanxing.commons.model.main.VaServerInfo;
import com.viontech.fanxing.task.model.TaskData;
import com.viontech.fanxing.task.model.runtime.DailyRuntimeConfig;
import com.viontech.fanxing.task.model.runtime.RandomRuntimeConfig;
import com.viontech.fanxing.task.model.runtime.RuntimeConfig;
import com.viontech.fanxing.task.service.TaskDataService;
import com.viontech.fanxing.task.service.VAServerService;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RMap;

import java.time.LocalTime;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * .
 *
 * @author 谢明辉
 * @date 2021/12/21
 */
@SuppressWarnings("ALL")
@Slf4j
public enum TaskUtils {
    INSTANCE;

    /**
     * 判断任务是否可以执行
     * 没有场景存储配置,状态是停止或未部署的都不能运行
     */
    public boolean canRun(Task task) {
        return StringUtils.isNotBlank(task.getScene()) && task.getStoreConfigId() != null && !TaskStatus.AWAIT.valEqual(task.getStatus()) && !TaskStatus.STOP.valEqual(task.getStatus());
    }

    /**
     * 判断任务是否需要被重新构建
     *
     * @param original 之前的任务信息
     * @param present  现在的任务信息
     */
    public boolean needRebuild(Task original, Task present) {
        return (!Objects.equals(original.getRuntimeConf(), present.getRuntimeConf()))
                || (!Objects.equals(original.getStoreConfigId(), present.getStoreConfigId()))
                || (!Objects.equals(original.getResourceNeed(), present.getResourceNeed()))
                || (!Objects.equals(original.getVaType(), present.getVaType()));
    }

    public void checkRuntimeConf(TaskData taskData, VAServerService vaServerService, TaskDataService taskDataService) {
        Integer runtimeType = taskData.getTask().getRuntimeType();
        TaskExample taskExample = new TaskExample();
        taskExample.createCriteria().andStatusIn(ListUtil.of(TaskStatus.STARTING.val, TaskStatus.STAY.val, TaskStatus.RUNNING.val, TaskStatus.CAN_NOT_RUN.val));
        List<Task> tasks = taskDataService.getTaskService().selectByExample(taskExample);
        RMap<String, VaServerInfo> map = vaServerService.getVaServerRedisRepository().getVaServerInfoMap();
        // 初始化资源检查对象
        final TaskChecking taskChecking = new TaskChecking();
        map.values().stream().forEach(x -> taskChecking.addServer(x));
        tasks.stream().filter(x -> x.getId() != taskData.getTask().getId()).map(x -> new TaskData(x)).forEach(x -> taskChecking.addTask(x));
        taskChecking.addTask(taskData);
    }

    private @Getter
    @Setter
    static class TaskChecking {
        private ArrayListMultimap<String, ResourceNode> serverResourceMap = ArrayListMultimap.create();

        public void addTask(TaskData taskData) {
            String vaType = taskData.getTask().getVaType();
            Integer runtimeType = taskData.getTask().getRuntimeType();
            RuntimeConfig runtimeConfig = taskData.getRuntimeConfig();
            Float resourceNeed = taskData.getTask().getResourceNeed();
            Collection<ResourceNode> nodes;
            if (vaType == null) {
                nodes = serverResourceMap.values();
            } else {
                nodes = serverResourceMap.get(vaType);
            }
            boolean success = false;
            switch (runtimeType) {
                case 4:
                    if (reduce(nodes, resourceNeed, 0, ResourceNode.MAX_SECOND)) {
                        return;
                    }
                    break;
                case 0:
                    DailyRuntimeConfig dConfig = (DailyRuntimeConfig) runtimeConfig;
                    List<RuntimeConfig.Config> multiConfig = dConfig.getMultiConfig();
                    for (RuntimeConfig.Config config : multiConfig) {
                        LocalTime start = config.getStart();
                        LocalTime end = config.getEnd();
                        if (reduce(nodes, resourceNeed, start.toSecondOfDay(), end.toSecondOfDay())) {
                            success = true;
                        } else {
                            break;
                        }
                    }
                    if (success) {
                        return;
                    } else {
                        break;
                    }

                case 3:
                    RandomRuntimeConfig rConfig = (RandomRuntimeConfig) runtimeConfig;
                    Long runningTime = rConfig.getRunningTime();
                    long runSecond = (int) TimeUnit.MINUTES.toSeconds(runningTime);
                    int nowSecond = LocalTime.now().toSecondOfDay();
                    if (runSecond > 86400) {
                        success = reduce(nodes, resourceNeed, 0, ResourceNode.MAX_SECOND);
                    } else if ((nowSecond + runSecond) > ResourceNode.MAX_SECOND) {
                        success = reduce(nodes, resourceNeed, nowSecond, ResourceNode.MAX_SECOND);
                        if (success) {
                            reduce(nodes, resourceNeed, 0, (int) ((nowSecond + runSecond) - ResourceNode.MAX_SECOND));
                        }
                    } else {
                        success = reduce(nodes, resourceNeed, nowSecond, (int) (nowSecond + runSecond));
                    }
                    if (success) {
                        return;
                    }
                    break;
            }
            log.error("任务无法启动,");
            throw new FanXingException("任务资源信息异常");
        }

        private boolean reduce(Collection<ResourceNode> resourceNodes, Float resourceNeed, int start, int end) {
            for (ResourceNode node : resourceNodes) {
                if (node.reduce(resourceNeed, start, end)) {
                    return true;
                }
            }
            return false;
        }

        public void addServer(VaServerInfo vaServerInfo) {
            ResourceNode resourceNode = new ResourceNode(vaServerInfo);
            serverResourceMap.put(vaServerInfo.getPlatType(), resourceNode);
        }
    }

    private @Getter
    @Setter
    @NoArgsConstructor
    static class ResourceNode {
        public static final Integer MAX_SECOND = 24 * 60 * 60 - 1;
        /** min index 0; max index 86399 */
        private Float[] resource;
        private Float max;
        private String devId;

        public ResourceNode(VaServerInfo vaServerInfo) {
            Float availableResources = vaServerInfo.getVideoResource();
            this.devId = vaServerInfo.getDevID();
            resource = new Float[86400];
            for (int i = 0; i < resource.length; i++) {
                resource[i] = availableResources;
            }
            this.max = availableResources;
        }

        /**
         * @param start include
         * @param end   exclude
         */
        public boolean reduce(Float value, int start, int end) {
            for (int i = start; i < end; i++) {
                if (!(resource[i] >= value)) {
                    return false;
                }
            }
            for (int i = start; i < end; i++) {
                resource[i] = resource[i] - value;
            }
            return true;
        }
    }


}