新增主设备部件根据cron表达式自动创建任务
This commit is contained in:
parent
87c6d31eb4
commit
26a4b19724
@ -11,6 +11,7 @@ import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.text.ParseException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -32,7 +33,8 @@ public class AlgorithmClassComponentController {
|
||||
|
||||
@GetMapping("/getAlgorithmClassComponentPage")
|
||||
@ApiOperation("算法关联主设备部件")
|
||||
public ResponseResult getAlgorithmClassComponentPage(String algorithmId,String stationCode, Page<AlgorithmClassComponent> page) {
|
||||
public ResponseResult getAlgorithmClassComponentPage(String algorithmId, String stationCode,
|
||||
Page<AlgorithmClassComponent> page) {
|
||||
Page<AlgorithmClassComponent> algorithmClassComponentPage =
|
||||
algorithmClassComponentService.getAlgorithmClassComponentPage(algorithmId, stationCode, page);
|
||||
return ResponseResult.successData(algorithmClassComponentPage);
|
||||
@ -59,4 +61,11 @@ public class AlgorithmClassComponentController {
|
||||
return ResponseResult.error();
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/setAlgorithmClassComponentStatus")
|
||||
@ApiOperation("设置算法关联主设备部件状态")
|
||||
public ResponseResult setAlgorithmClassComponentStatus(String id, String isenable) throws ParseException {
|
||||
boolean isOK = algorithmClassComponentService.setAlgorithmClassComponentStatus(id, isenable);
|
||||
return ResponseResult.success();
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package com.yfd.platform.modules.algorithm.domain;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
@ -105,5 +106,15 @@ public class AlgorithmClassComponent implements Serializable {
|
||||
@ApiModelProperty("部件名称")
|
||||
private String componentName;
|
||||
|
||||
/**
|
||||
* 是否可用;0:初始状态;1:启用
|
||||
*/
|
||||
@ApiModelProperty("是否可用;0:初始状态;1:启用")
|
||||
private String isenable;
|
||||
|
||||
/**
|
||||
* cron表达式
|
||||
*/
|
||||
@ApiModelProperty("cron表达式")
|
||||
private String cronValue;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.yfd.platform.modules.algorithm.domain.AlgorithmClassComponent;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -33,4 +34,7 @@ public interface IAlgorithmClassComponentService extends IService<AlgorithmClass
|
||||
|
||||
boolean batchAddAlgorithmClassComponent(List<AlgorithmClassComponent> algorithmClassComponentList);
|
||||
|
||||
boolean setAlgorithmClassComponentStatus(String id, String isenable) throws ParseException;
|
||||
|
||||
boolean createAlgorithmTaskList(AlgorithmClassComponent algorithmClassComponent) throws ParseException;
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
package com.yfd.platform.modules.algorithm.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.yfd.platform.modules.algorithm.domain.AlgorithmClassComponent;
|
||||
@ -9,9 +12,17 @@ import com.yfd.platform.modules.algorithm.domain.AlgorithmDevice;
|
||||
import com.yfd.platform.modules.algorithm.mapper.AlgorithmClassComponentMapper;
|
||||
import com.yfd.platform.modules.algorithm.mapper.AlgorithmDeviceMapper;
|
||||
import com.yfd.platform.modules.algorithm.service.IAlgorithmClassComponentService;
|
||||
import com.yfd.platform.modules.patroltask.domain.TaskTodo;
|
||||
import com.yfd.platform.utils.CronScheduleUtils;
|
||||
import org.quartz.CronExpression;
|
||||
import org.quartz.TriggerUtils;
|
||||
import org.quartz.impl.triggers.CronTriggerImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.text.ParseException;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -29,6 +40,9 @@ public class AlgorithmClassComponentServiceImpl extends ServiceImpl<AlgorithmCla
|
||||
@Resource
|
||||
private AlgorithmDeviceMapper algorithmDeviceMapper;
|
||||
|
||||
@Resource
|
||||
private AlgorithmTaskManager algorithmTaskManager;
|
||||
|
||||
/**********************************
|
||||
* 用途说明: 算法关联主设备部件
|
||||
* 参数说明 algorithmId 算法分类id
|
||||
@ -69,4 +83,75 @@ public class AlgorithmClassComponentServiceImpl extends ServiceImpl<AlgorithmCla
|
||||
public boolean batchAddAlgorithmClassComponent(List<AlgorithmClassComponent> algorithmClassComponentList) {
|
||||
return this.saveOrUpdateBatch(algorithmClassComponentList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setAlgorithmClassComponentStatus(String id, String isenable) throws ParseException {
|
||||
AlgorithmClassComponent algorithmClassComponent = this.getById(id);
|
||||
|
||||
if (algorithmClassComponent == null) {
|
||||
return false;
|
||||
}
|
||||
if (isenable.equals(algorithmClassComponent.getIsenable())) {
|
||||
throw new RuntimeException("当前状态与要设置的状态一致");
|
||||
}
|
||||
if ("1".equals(isenable)) {
|
||||
//TODO 根据cron表达式设置定时任务
|
||||
this.createAlgorithmTaskList(algorithmClassComponent);
|
||||
}
|
||||
if ("0".equals(isenable)) {
|
||||
this.deleteAllTasksByComponentId(algorithmClassComponent);
|
||||
}
|
||||
LambdaUpdateWrapper<AlgorithmClassComponent> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(AlgorithmClassComponent::getId, id).set(AlgorithmClassComponent::getIsenable, isenable);
|
||||
return this.update(updateWrapper);
|
||||
}
|
||||
|
||||
private void deleteAllTasksByComponentId(AlgorithmClassComponent component) {
|
||||
// 调用 Quartz 工具类删除任务
|
||||
try {
|
||||
algorithmTaskManager.deleteAllTasksByComponentId(component.getId(), component.getStationCode());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("删除定时任务失败:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createAlgorithmTaskList(AlgorithmClassComponent algorithmClassComponent) throws ParseException {
|
||||
// 判断cron表达式有效性
|
||||
if (StrUtil.isBlank(algorithmClassComponent.getCronValue())) {
|
||||
return false;
|
||||
}
|
||||
String cronValue = algorithmClassComponent.getCronValue();
|
||||
if (!CronExpression.isValidExpression(cronValue)) {
|
||||
throw new RuntimeException("cron表达式格式错误");
|
||||
}
|
||||
List<Date> fireTimes = CronScheduleUtils.getFireTimes(cronValue, 30);
|
||||
// 判断是否有定时任务
|
||||
if (fireTimes.isEmpty()) {
|
||||
throw new RuntimeException("当前cron表达式没有生成任务");
|
||||
}
|
||||
if (fireTimes.size() > 180) {
|
||||
throw new RuntimeException("当前cron表达式生成任务数量超过最大数量");
|
||||
}
|
||||
for (Date fireTime : fireTimes) {
|
||||
setToDoTask(algorithmClassComponent, DateUtil.formatDateTime(fireTime));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置待办任务的时间
|
||||
* 此方法用于根据提供的算法类组件和触发时间来安排待办任务
|
||||
* 它不返回任何值,但可能根据需要更新或创建待办任务
|
||||
*
|
||||
* @param algorithmClassComponent 算法类组件,代表需要执行的任务的类型或相关信息
|
||||
* @param fireTime 任务触发时间,采用字符串形式,具体的格式需要根据上下文或文档确定
|
||||
*/
|
||||
private void setToDoTask(AlgorithmClassComponent algorithmClassComponent, String fireTime) {
|
||||
try {
|
||||
algorithmTaskManager.addTask(algorithmClassComponent, fireTime);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("添加定时任务失败:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
package com.yfd.platform.modules.algorithm.service.impl;
|
||||
|
||||
import com.yfd.platform.modules.algorithm.domain.AlgorithmClassComponent;
|
||||
import com.yfd.platform.modules.algorithm.service.IAlgorithmParamsService;
|
||||
import com.yfd.platform.utils.SpringContextHolder;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
|
||||
public class AlgorithmTaskJob implements Job {
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException {
|
||||
|
||||
IAlgorithmParamsService algorithmParamsService = SpringContextHolder.getBean(IAlgorithmParamsService.class);
|
||||
|
||||
// 获取传递的任务参数
|
||||
Object jobData = context.getMergedJobDataMap().get("algorithmClassComponent");
|
||||
if (jobData instanceof AlgorithmClassComponent) {
|
||||
AlgorithmClassComponent component = (AlgorithmClassComponent) jobData;
|
||||
algorithmParamsService.callAlgorithmAnalyse(component.getAlgorithmId(), component.getComponentId());
|
||||
System.out.println("执行算法任务:" + component.getComponentId() +
|
||||
",触发时间:" + context.getScheduledFireTime());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
package com.yfd.platform.modules.algorithm.service.impl;
|
||||
|
||||
import com.yfd.platform.modules.algorithm.domain.AlgorithmClassComponent;
|
||||
import org.quartz.*;
|
||||
import org.quartz.impl.DirectSchedulerFactory;
|
||||
import org.quartz.impl.StdSchedulerFactory;
|
||||
import org.quartz.impl.matchers.GroupMatcher;
|
||||
import org.quartz.simpl.RAMJobStore;
|
||||
import org.quartz.simpl.SimpleThreadPool;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 算法任务管理器
|
||||
*/
|
||||
@Component
|
||||
public class AlgorithmTaskManager {
|
||||
|
||||
private static final String JOB_NAME_PREFIX = "ALGORITHM_COMPONENT_";
|
||||
private static final String JOB_GROUP_PREFIX = "STATION_";
|
||||
|
||||
// 存储每个 stationCode 对应的 Scheduler
|
||||
private Map<String, Scheduler> schedulers = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 添加定时任务
|
||||
*
|
||||
* @param component 算法类组件
|
||||
* @param fireTime 触发时间(格式:yyyy-MM-dd HH:mm:ss)
|
||||
*/
|
||||
public void addTask(AlgorithmClassComponent component, String fireTime) throws Exception {
|
||||
String stationCode = component.getStationCode();
|
||||
String jobId = component.getId();
|
||||
|
||||
Scheduler scheduler = getOrCreateScheduler(stationCode);
|
||||
|
||||
// 使用 jobId + fireTime.hashCode() 构建唯一任务 Key
|
||||
String uniqueKey = jobId + "_" + fireTime.hashCode();
|
||||
JobKey jobKey = JobKey.jobKey(JOB_NAME_PREFIX + uniqueKey, JOB_GROUP_PREFIX + stationCode);
|
||||
TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME_PREFIX + uniqueKey, JOB_GROUP_PREFIX + stationCode);
|
||||
|
||||
// 如果任务已存在,先删除
|
||||
if (scheduler.checkExists(jobKey)) {
|
||||
scheduler.pauseJob(jobKey);
|
||||
scheduler.unscheduleJob(triggerKey);
|
||||
scheduler.deleteJob(jobKey);
|
||||
}
|
||||
|
||||
// 创建任务详情
|
||||
JobDetail jobDetail = JobBuilder.newJob(AlgorithmTaskJob.class)
|
||||
.withIdentity(jobKey)
|
||||
.build();
|
||||
|
||||
Date planDate = org.apache.commons.lang3.time.DateUtils.parseDate(fireTime, "yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
// 创建一次性触发器
|
||||
Trigger trigger = TriggerBuilder.newTrigger()
|
||||
.withIdentity(triggerKey)
|
||||
.startAt(planDate)
|
||||
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
|
||||
.withRepeatCount(0))
|
||||
.build();
|
||||
|
||||
// 传递参数给任务
|
||||
jobDetail.getJobDataMap().put("algorithmClassComponent", component);
|
||||
|
||||
// 注册并启动任务
|
||||
scheduler.scheduleJob(jobDetail, trigger);
|
||||
scheduler.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定ID的所有任务
|
||||
*
|
||||
* @param id 主设备部件ID
|
||||
*/
|
||||
/**
|
||||
* 删除指定算法组件的所有定时任务(基于 jobId 前缀匹配)
|
||||
*
|
||||
* @param id 主设备部件ID
|
||||
* @param stationCode 变电站编码
|
||||
*/
|
||||
public void deleteAllTasksByComponentId(String id, String stationCode) throws Exception {
|
||||
Scheduler scheduler = getOrCreateScheduler(stationCode);
|
||||
|
||||
// 构建任务名前缀,如 ALGORITHM_COMPONENT_123_
|
||||
String jobNamePrefix = JOB_NAME_PREFIX + id + "_";
|
||||
GroupMatcher<JobKey> matcher = GroupMatcher.jobGroupEquals(JOB_GROUP_PREFIX + stationCode);
|
||||
|
||||
for (JobKey jobKey : scheduler.getJobKeys(matcher)) {
|
||||
if (jobKey.getName().startsWith(jobNamePrefix)) {
|
||||
try {
|
||||
// 获取所有关联触发器
|
||||
List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
|
||||
for (Trigger trigger : triggers) {
|
||||
TriggerKey triggerKey = trigger.getKey();
|
||||
// 暂停触发器
|
||||
scheduler.pauseTrigger(triggerKey);
|
||||
// 移除触发器
|
||||
scheduler.unscheduleJob(triggerKey);
|
||||
}
|
||||
scheduler.deleteJob(jobKey); // 删除任务
|
||||
System.out.println("成功删除任务:" + jobKey);
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("删除任务失败:" + jobKey + ",原因:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取或创建指定变电站的调度器
|
||||
*/
|
||||
private Scheduler getOrCreateScheduler(String stationCode) throws Exception {
|
||||
Scheduler scheduler = schedulers.get(stationCode);
|
||||
if (scheduler == null || !scheduler.isStarted()) {
|
||||
DirectSchedulerFactory factory = DirectSchedulerFactory.getInstance();
|
||||
factory.createScheduler(stationCode, stationCode,
|
||||
new SimpleThreadPool(5, Thread.NORM_PRIORITY),
|
||||
new RAMJobStore());
|
||||
scheduler = factory.getScheduler(stationCode);
|
||||
schedulers.put(stationCode, scheduler);
|
||||
}
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭所有调度器
|
||||
*/
|
||||
public void shutdownAllSchedulers() throws SchedulerException {
|
||||
for (Scheduler scheduler : schedulers.values()) {
|
||||
if (scheduler.isStarted()) {
|
||||
scheduler.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.yfd.platform.utils;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import org.quartz.CronExpression;
|
||||
import org.quartz.TriggerUtils;
|
||||
import org.quartz.impl.triggers.CronTriggerImpl;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class CronScheduleUtils {
|
||||
|
||||
public static List<Date> getFireTimes(String cron, int futureDays) throws ParseException {
|
||||
if (!CronExpression.isValidExpression(cron)) {
|
||||
throw new IllegalArgumentException("Invalid cron expression: " + cron);
|
||||
}
|
||||
|
||||
CronTriggerImpl trigger = new CronTriggerImpl();
|
||||
trigger.setCronExpression(cron);
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
LocalDateTime endDate = now.plusDays(futureDays).with(LocalTime.MAX);
|
||||
|
||||
Date beginDate = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
|
||||
Date endDateAsDate = Date.from(endDate.atZone(ZoneId.systemDefault()).toInstant());
|
||||
return TriggerUtils.computeFireTimesBetween(trigger, null, beginDate, endDateAsDate);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
List<Date> fireTimes = getFireTimes("30 54,55,56,57,58 17 ? 6 5 ", 30);
|
||||
for (Date fireTime : fireTimes) {
|
||||
// 将时间转成yyyy-MM-dd HH:mm:ss格式的时间字符串
|
||||
String fireTimeStr = LocalDateTimeUtil.format(LocalDateTimeUtil.of(fireTime), DatePattern.NORM_DATETIME_PATTERN);
|
||||
System.out.println(fireTimeStr);
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user