|
|
|
@ -1,142 +1,283 @@
|
|
|
|
// TaskSchedulerManager.java
|
|
|
|
// TaskSchedulerManager.java
|
|
|
|
package cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.scheduler;
|
|
|
|
package cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.scheduler;
|
|
|
|
|
|
|
|
|
|
|
|
import cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.coretask.DeviceTask;
|
|
|
|
import cn.iocoder.yudao.module.iot.controller.admin.device.enums.TaskTypeEnum;
|
|
|
|
|
|
|
|
import cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.core.Task;
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
import org.springframework.scheduling.TaskScheduler;
|
|
|
|
import org.springframework.scheduling.TaskScheduler;
|
|
|
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
|
|
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
|
|
|
import org.springframework.scheduling.support.CronTrigger;
|
|
|
|
import org.springframework.scheduling.support.CronTrigger;
|
|
|
|
|
|
|
|
import org.springframework.scheduling.support.PeriodicTrigger;
|
|
|
|
import org.springframework.stereotype.Component;
|
|
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
|
|
|
|
|
|
|
import javax.annotation.PostConstruct;
|
|
|
|
import javax.annotation.PostConstruct;
|
|
|
|
|
|
|
|
import java.time.Duration;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
import java.util.concurrent.ScheduledFuture;
|
|
|
|
import java.util.concurrent.ScheduledFuture;
|
|
|
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
|
|
|
|
@Component
|
|
|
|
@Component
|
|
|
|
public class TaskSchedulerManager {
|
|
|
|
public class TaskSchedulerManager {
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(TaskSchedulerManager.class);
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(TaskSchedulerManager.class);
|
|
|
|
|
|
|
|
|
|
|
|
private TaskScheduler taskScheduler; // 移除 static
|
|
|
|
private final TaskScheduler taskScheduler;
|
|
|
|
private DeviceTask deviceTask; // 移除 static
|
|
|
|
|
|
|
|
private final Map<Long, ScheduledFuture<?>> taskMap = new ConcurrentHashMap<>();
|
|
|
|
// 存储所有任务
|
|
|
|
|
|
|
|
private final Map<String, Task> taskBeans = new ConcurrentHashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 存储正在运行的任务
|
|
|
|
|
|
|
|
private final Map<Long, ScheduledFuture<?>> runningTasks = new ConcurrentHashMap<>();
|
|
|
|
|
|
|
|
private final Map<Long, TaskInfo> taskInfos = new ConcurrentHashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 任务信息类
|
|
|
|
|
|
|
|
private static class TaskInfo {
|
|
|
|
|
|
|
|
private Long taskId;
|
|
|
|
|
|
|
|
private String taskType;
|
|
|
|
|
|
|
|
private String taskParam;
|
|
|
|
|
|
|
|
private String cronExpression;
|
|
|
|
|
|
|
|
private String scheduleType; // "CRON" 或 "FIXED_RATE" 或 "FIXED_DELAY"
|
|
|
|
|
|
|
|
private Long initialDelay;
|
|
|
|
|
|
|
|
private Long period;
|
|
|
|
|
|
|
|
private TimeUnit timeUnit;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 构造器
|
|
|
|
|
|
|
|
public TaskInfo(Long taskId, String taskType, String taskParam) {
|
|
|
|
|
|
|
|
this.taskId = taskId;
|
|
|
|
|
|
|
|
this.taskType = taskType;
|
|
|
|
|
|
|
|
this.taskParam = taskParam;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// getters and setters...
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 通过构造器注入
|
|
|
|
|
|
|
|
public TaskSchedulerManager(TaskScheduler taskScheduler,
|
|
|
|
|
|
|
|
@Autowired(required = false) java.util.List<Task> tasks) {
|
|
|
|
|
|
|
|
this.taskScheduler = taskScheduler;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 注册所有任务
|
|
|
|
|
|
|
|
if (tasks != null) {
|
|
|
|
|
|
|
|
for (Task task : tasks) {
|
|
|
|
|
|
|
|
taskBeans.put(task.getTaskType(), task);
|
|
|
|
|
|
|
|
logger.info("注册任务类型: {}", task.getTaskType());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* 通过构造器注入 TaskScheduler
|
|
|
|
* 启动 Cron 定时任务
|
|
|
|
* Spring 会自动在上下文中查找 TaskScheduler Bean
|
|
|
|
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
@Autowired
|
|
|
|
public boolean startCronTask(Long taskId, String taskType, String taskParam, String cronExpression) {
|
|
|
|
public TaskSchedulerManager(TaskScheduler taskScheduler) {
|
|
|
|
return startTask(taskId, taskType, taskParam, "CRON", cronExpression, null, null, null);
|
|
|
|
this.taskScheduler = taskScheduler;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* 注入 DeviceTask
|
|
|
|
* 启动固定频率任务
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
@Autowired
|
|
|
|
public boolean startFixedRateTask(Long taskId, String taskType, String taskParam,
|
|
|
|
public void setDeviceTask(DeviceTask deviceTask) {
|
|
|
|
long initialDelay, long period, TimeUnit timeUnit) {
|
|
|
|
this.deviceTask = deviceTask;
|
|
|
|
return startTask(taskId, taskType, taskParam, "FIXED_RATE", null,
|
|
|
|
|
|
|
|
initialDelay, period, timeUnit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* 如果 Spring 容器中没有 TaskScheduler Bean,
|
|
|
|
* 启动固定延迟任务
|
|
|
|
* 可以在这里创建一个默认的
|
|
|
|
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
@PostConstruct
|
|
|
|
public boolean startFixedDelayTask(Long taskId, String taskType, String taskParam,
|
|
|
|
public void init() {
|
|
|
|
long initialDelay, long period, TimeUnit timeUnit) {
|
|
|
|
if (taskScheduler == null) {
|
|
|
|
return startTask(taskId, taskType, taskParam, "FIXED_DELAY", null,
|
|
|
|
logger.warn("TaskScheduler not found in context, creating default one");
|
|
|
|
initialDelay, period, timeUnit);
|
|
|
|
ThreadPoolTaskScheduler defaultScheduler = new ThreadPoolTaskScheduler();
|
|
|
|
|
|
|
|
defaultScheduler.setPoolSize(10);
|
|
|
|
|
|
|
|
defaultScheduler.setThreadNamePrefix("device-task-");
|
|
|
|
|
|
|
|
defaultScheduler.initialize();
|
|
|
|
|
|
|
|
this.taskScheduler = defaultScheduler;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* 启动设备定时任务
|
|
|
|
* 通用启动任务方法
|
|
|
|
* 移除 static 修饰符
|
|
|
|
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public boolean startDeviceTask(Long deviceId, String deviceCode, String cronExpression) {
|
|
|
|
private boolean startTask(Long taskId, String taskType, String taskParam,
|
|
|
|
|
|
|
|
String scheduleType, String cronExpression,
|
|
|
|
|
|
|
|
Long initialDelay, Long period, TimeUnit timeUnit) {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
// 先停止已存在的任务
|
|
|
|
// 停止已存在的任务
|
|
|
|
stopDeviceTask(deviceId);
|
|
|
|
stopTask(taskId);
|
|
|
|
|
|
|
|
|
|
|
|
// 验证 DeviceTask
|
|
|
|
// 获取任务实例
|
|
|
|
if (deviceTask == null) {
|
|
|
|
Task task = taskBeans.get(taskType);
|
|
|
|
logger.error("DeviceTask is not initialized");
|
|
|
|
if (task == null) {
|
|
|
|
|
|
|
|
logger.error("任务类型不存在: {}", taskType);
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建新的定时任务
|
|
|
|
// 创建任务信息
|
|
|
|
ScheduledFuture<?> future = taskScheduler.schedule(
|
|
|
|
TaskInfo taskInfo = new TaskInfo(taskId, taskType, taskParam);
|
|
|
|
() -> {
|
|
|
|
taskInfo.scheduleType = scheduleType;
|
|
|
|
try {
|
|
|
|
taskInfo.cronExpression = cronExpression;
|
|
|
|
deviceTask.executeDeviceLogic(deviceId, deviceCode);
|
|
|
|
taskInfo.initialDelay = initialDelay;
|
|
|
|
} catch (Exception e) {
|
|
|
|
taskInfo.period = period;
|
|
|
|
logger.error("Device task execution failed for deviceId: {}", deviceId, e);
|
|
|
|
taskInfo.timeUnit = timeUnit;
|
|
|
|
}
|
|
|
|
taskInfos.put(taskId, taskInfo);
|
|
|
|
},
|
|
|
|
|
|
|
|
new CronTrigger(cronExpression)
|
|
|
|
// 根据调度类型创建任务
|
|
|
|
);
|
|
|
|
ScheduledFuture<?> future = null;
|
|
|
|
|
|
|
|
switch (scheduleType) {
|
|
|
|
taskMap.put(deviceId, future);
|
|
|
|
case "CRON":
|
|
|
|
logger.info("启动设备定时任务成功,设备ID: {}, cron表达式: {}", deviceId, cronExpression);
|
|
|
|
future = taskScheduler.schedule(
|
|
|
|
return true;
|
|
|
|
() -> task.execute(taskId, taskParam),
|
|
|
|
|
|
|
|
new CronTrigger(cronExpression)
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "FIXED_RATE":
|
|
|
|
|
|
|
|
if (initialDelay != null && period != null && timeUnit != null) {
|
|
|
|
|
|
|
|
future = taskScheduler.scheduleAtFixedRate(
|
|
|
|
|
|
|
|
() -> task.execute(taskId, taskParam),
|
|
|
|
|
|
|
|
initialDelay
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "FIXED_DELAY":
|
|
|
|
|
|
|
|
if (initialDelay != null && period != null && timeUnit != null) {
|
|
|
|
|
|
|
|
future = taskScheduler.scheduleWithFixedDelay(
|
|
|
|
|
|
|
|
() -> task.execute(taskId, taskParam),
|
|
|
|
|
|
|
|
initialDelay
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (future != null) {
|
|
|
|
|
|
|
|
runningTasks.put(taskId, future);
|
|
|
|
|
|
|
|
logger.info("启动{}任务成功,任务ID: {}, 类型: {}, 参数: {}",
|
|
|
|
|
|
|
|
scheduleType, taskId, taskType, taskParam);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
} catch (Exception e) {
|
|
|
|
logger.error("启动设备定时任务失败,设备ID: {}", deviceId, e);
|
|
|
|
logger.error("启动任务失败,任务ID: {}", taskId, e);
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* 停止设备定时任务
|
|
|
|
* 停止任务
|
|
|
|
* 移除 static 修饰符
|
|
|
|
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public boolean stopDeviceTask(Long deviceId) {
|
|
|
|
public boolean stopTask(Long taskId) {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
ScheduledFuture<?> future = taskMap.get(deviceId);
|
|
|
|
ScheduledFuture<?> future = runningTasks.get(taskId);
|
|
|
|
if (future != null) {
|
|
|
|
if (future != null) {
|
|
|
|
future.cancel(true);
|
|
|
|
future.cancel(true);
|
|
|
|
taskMap.remove(deviceId);
|
|
|
|
runningTasks.remove(taskId);
|
|
|
|
logger.info("停止设备定时任务成功,设备ID: {}", deviceId);
|
|
|
|
taskInfos.remove(taskId);
|
|
|
|
|
|
|
|
logger.info("停止任务成功,任务ID: {}", taskId);
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
|
|
|
|
logger.info("设备定时任务不存在,设备ID: {}", deviceId);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
} catch (Exception e) {
|
|
|
|
} catch (Exception e) {
|
|
|
|
logger.error("停止设备定时任务失败,设备ID: {}", deviceId, e);
|
|
|
|
logger.error("停止任务失败,任务ID: {}", taskId, e);
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* 检查设备定时任务是否在运行
|
|
|
|
* 获取任务信息
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public TaskInfo getTaskInfo(Long taskId) {
|
|
|
|
|
|
|
|
return taskInfos.get(taskId);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 检查任务是否运行
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public boolean isTaskRunning(Long deviceId) {
|
|
|
|
public boolean isTaskRunning(Long taskId) {
|
|
|
|
ScheduledFuture<?> future = taskMap.get(deviceId);
|
|
|
|
ScheduledFuture<?> future = runningTasks.get(taskId);
|
|
|
|
return future != null && !future.isCancelled() && !future.isDone();
|
|
|
|
return future != null && !future.isCancelled() && !future.isDone();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* 获取任务数量
|
|
|
|
* 获取所有任务类型
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public int getTaskCount() {
|
|
|
|
public Map<String, Task> getAllTaskTypes() {
|
|
|
|
return taskMap.size();
|
|
|
|
return new ConcurrentHashMap<>(taskBeans);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 获取运行中的任务数量
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public int getRunningTaskCount() {
|
|
|
|
|
|
|
|
return runningTasks.size();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* 停止所有任务
|
|
|
|
* 停止所有任务
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public void stopAllTasks() {
|
|
|
|
public void stopAllTasks() {
|
|
|
|
logger.info("停止所有定时任务,共 {} 个", taskMap.size());
|
|
|
|
logger.info("停止所有定时任务,共 {} 个", runningTasks.size());
|
|
|
|
for (Long deviceId : taskMap.keySet()) {
|
|
|
|
for (Long taskId : runningTasks.keySet()) {
|
|
|
|
stopDeviceTask(deviceId);
|
|
|
|
stopTask(taskId);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// /**
|
|
|
|
|
|
|
|
// * 原设备任务方法(保持兼容性)
|
|
|
|
|
|
|
|
// */
|
|
|
|
|
|
|
|
// public boolean startDeviceTask(Long deviceId, String deviceCode, String cronExpression) {
|
|
|
|
|
|
|
|
// String taskParam = deviceId + ":" + deviceCode;
|
|
|
|
|
|
|
|
// return startCronTask(deviceId, TaskTypeEnum.DEVICE.getCode(), taskParam, cronExpression);
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 启动设备任务
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public boolean startDeviceTask(Long deviceId, String cronExpression) {
|
|
|
|
|
|
|
|
Long taskId = TaskTypeEnum.DEVICE.generateTaskId(deviceId);
|
|
|
|
|
|
|
|
return startCronTask(taskId, TaskTypeEnum.DEVICE.getCode(),
|
|
|
|
|
|
|
|
"device:" + deviceId, cronExpression);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 停止设备任务
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public boolean stopDeviceTask(Long deviceId) {
|
|
|
|
|
|
|
|
if (deviceId == null) {
|
|
|
|
|
|
|
|
logger.warn("设备ID不能为空");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 生成与启动时相同的任务ID
|
|
|
|
|
|
|
|
Long taskId = TaskTypeEnum.DEVICE.generateTaskId(deviceId);
|
|
|
|
|
|
|
|
logger.info("停止设备任务,设备ID: {}, 生成的任务ID: {}", deviceId, taskId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return stopTask(taskId);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 启动工单任务
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public boolean startWorkOrderTask(Long configId, String cronExpression) {
|
|
|
|
|
|
|
|
Long taskId = TaskTypeEnum.WORK_ORDER.generateTaskId(configId);
|
|
|
|
|
|
|
|
return startCronTask(taskId, TaskTypeEnum.WORK_ORDER.getCode(),
|
|
|
|
|
|
|
|
"workOrder:" + configId, cronExpression);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 停止工单任务
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public boolean stopWorkOrderTask(Long configId) {
|
|
|
|
|
|
|
|
if (configId == null) {
|
|
|
|
|
|
|
|
logger.warn("工单配置ID不能为空");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 生成与启动时相同的任务ID
|
|
|
|
|
|
|
|
Long taskId = TaskTypeEnum.WORK_ORDER.generateTaskId(configId);
|
|
|
|
|
|
|
|
logger.info("停止工单任务,配置ID: {}, 生成的任务ID: {}", configId, taskId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return stopTask(taskId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|