Commit bdb2918e authored by wanghao's avatar wanghao

Revert "1 测试 上电后通信 和 最终完成 定时任务功能"

parent a80d6ec5
......@@ -342,7 +342,7 @@ public class TStoreyInfoServiceImpl implements ITStoreyInfoService
} else {
registerOffset = Arrays.asList(55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72);
}
deviceStatusReaderAndTimeSetter.startMultiDeviceMonitoring(split[0], Integer.parseInt(split[1]),registerOffset, modbusResultHandler, ModbusResultHandler.createDefaultStopCondition());
// deviceStatusReaderAndTimeSetter.startMultiDeviceMonitoring(split[0], Integer.parseInt(split[1]),registerOffset, modbusResultHandler, ModbusResultHandler.createDefaultStopCondition());
return null;
......
......@@ -31,8 +31,12 @@ public class DeviceTaskScheduler {
// 新增:每个设备任务的Quartz线程隔离(避免任务间干扰)
private static final String THREAD_GROUP = "DEVICE_THREAD_GROUP";
// 常量:Cron周期(5分钟)、任务有效期(7天)
private static final String CRON_EXPRESSION = "0 0/5 * * * ?";
private static final int TASK_VALID_DAYS = 7;
/**
* 创建设备监控任务(入口方法
* 创建设备监控任务(入口:增加调度器健康检查、任务去重
*/
public void scheduleDeviceMonitoring(Long fStoreyId, String fPowerOutageIp, Integer fPowerOutagePort) {
if (fStoreyId == null || fPowerOutageIp == null || fPowerOutagePort == null) {
......@@ -43,63 +47,64 @@ public class DeviceTaskScheduler {
try {
log.info("=== 开始创建设备监控任务:fStoreyId={} ===", fStoreyId);
// 1. 确保调度器已启动(若依框架可能延迟启动)
if (!scheduler.isStarted()) {
log.warn("调度器未启动,手动启动...");
scheduler.start();
}
// 1. 调度器健康检查(确保线程池可用)
checkSchedulerHealth();
// 关键:添加调度器状态监控,确保线程池可用
SchedulerMetaData metaData = scheduler.getMetaData();
log.info("Quartz线程池状态:核心线程={} 任务总数={}",
metaData.getThreadPoolSize(),
metaData.getNumberOfJobsExecuted());
// 2. 任务去重(避免重复创建导致资源竞争)
if (isTaskExists("COMM_" + fStoreyId)) {
log.info("通信任务[COMM_{}]已存在,无需重复创建", fStoreyId);
// 检查现有触发器状态,若为ERROR则重建
if (isTriggerError("COMM_" + fStoreyId)) {
log.warn("通信任务[COMM_{}]触发器状态为ERROR,重建触发器", fStoreyId);
createHourlyCommunicationJob(fStoreyId);
}
return;
}
// 2. 创建两个核心任务
// 3. 创建核心任务
createHourlyCommunicationJob(fStoreyId);
createFinalExecutionJob(fStoreyId, fPowerOutageIp, fPowerOutagePort);
// 3. 验证任务是否创建成功(关键:打印触发器状态)
checkTaskStatus(fStoreyId);
log.info("=== 设备监控任务创建完成:fStoreyId={} ===", fStoreyId);
} catch (SchedulerException e) {
log.error("=== 创建设备监控任务失败:fStoreyId={} ===", fStoreyId, e);
cleanInvalidTask(fStoreyId); // 失败时清理残留
throw new RuntimeException("Quartz任务调度失败", e);
}
}
/**
* 1. 创建每2分钟执行的通信任务(CronTrigger
* 1. 创建每5分钟执行的通信任务(核心优化:简化调度逻辑、调整Misfire策略
*/
private void createHourlyCommunicationJob(Long fStoreyId) throws SchedulerException {
String jobId = "COMM_" + fStoreyId;
JobKey jobKey = new JobKey(jobId, JOB_GROUP);
TriggerKey triggerKey = new TriggerKey(jobId + "_TRIGGER", TRIGGER_GROUP);
// 1. 构建JobDetail(仅定义任务元数据,不涉及调度规则
// 1. 构建JobDetail(仅元数据,禁止并发执行通过注解控制
JobDetail job = JobBuilder.newJob(DeviceCommunicationJob.class)
.withIdentity(jobKey)
.withDescription("设备" + fStoreyId + "每5分钟Modbus通信任务")
.usingJobData("fStoreyId", fStoreyId.toString())
.storeDurably(false)
.usingJobData("fStoreyId", fStoreyId.toString()) // 传递参数(String避免类型问题)
.storeDurably(false) // 触发器删除后Job自动失效
.requestRecovery(true) // 服务重启后恢复未完成任务
.build(); // 移除错误的 withSchedule() 调用
.build();
// 2. 构建CronTrigger(调度规则在此配置
// 2. 构建CronTrigger(移除withMisfireThreshold,兼容低版本
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerKey)
.forJob(jobKey)
.withDescription("设备" + fStoreyId + "通信任务触发器(每5分钟)")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?")
// 关键:Misfire策略(错过触发后忽略,避免集中执行
.withMisfireHandlingInstructionDoNothing())
.withSchedule(CronScheduleBuilder.cronSchedule(CRON_EXPRESSION)
// Misfire策略:错过触发后立即执行,再按原计划(低版本支持
.withMisfireHandlingInstructionFireAndProceed())
.startNow()
.endAt(Date.from(Instant.now().plus(7, ChronoUnit.DAYS))) // 7天有效期
.endAt(Date.from(Instant.now().plus(TASK_VALID_DAYS, ChronoUnit.DAYS)))
.build();
// 3. 原子操作:创建/更新任务
// 3. 原子操作:创建/更新(优先更新,避免删除重建)
if (scheduler.checkExists(jobKey)) {
Date nextFireTime = scheduler.rescheduleJob(triggerKey, trigger);
log.info("通信任务[{}]更新触发器成功,下次执行时间:{}", jobId, nextFireTime);
......@@ -109,15 +114,15 @@ public class DeviceTaskScheduler {
}
}
/**
* 2. 创建5分钟后执行的最终任务(SimpleTrigger,仅执行一次
* 2. 创建15分钟后执行的最终任务(保持原逻辑,优化超时
*/
private void createFinalExecutionJob(Long fStoreyId, String fPowerOutageIp, Integer fPowerOutagePort) throws SchedulerException {
String jobId = "FINAL_" + fStoreyId;
JobKey jobKey = new JobKey(jobId, JOB_GROUP);
TriggerKey triggerKey = new TriggerKey(jobId + "_TRIGGER", TRIGGER_GROUP);
// 构建JobDetail
JobDetail job = JobBuilder.newJob(FinalExecutionJob.class)
.withIdentity(jobKey)
.withDescription("设备" + fStoreyId + "最终执行任务(仅一次)")
......@@ -128,7 +133,6 @@ public class DeviceTaskScheduler {
.requestRecovery(true)
.build();
// 构建SimpleTrigger
Date executeTime = Date.from(Instant.now().plus(15, ChronoUnit.MINUTES));
SimpleTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerKey)
......@@ -136,11 +140,10 @@ public class DeviceTaskScheduler {
.withDescription("设备" + fStoreyId + "最终任务触发器")
.startAt(executeTime)
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withMisfireHandlingInstructionFireNow() // 错过触发立即执行
.withRepeatCount(0)) // 仅执行一次
.withMisfireHandlingInstructionFireNow() // 错过立即执行
.withRepeatCount(0)) // 仅一次
.build();
// 原子操作:创建/更新
if (scheduler.checkExists(jobKey)) {
Date nextFireTime = scheduler.rescheduleJob(triggerKey, trigger);
log.info("最终任务[{}]更新触发器成功,执行时间:{}", jobId, nextFireTime);
......@@ -149,6 +152,38 @@ public class DeviceTaskScheduler {
log.info("最终任务[{}]创建成功,执行时间:{}", jobId, nextFireTime);
}
}
// ------------------------------ 工具方法:增强稳定性 ------------------------------
/**
* 检查Quartz调度器健康状态(避免线程池耗尽)
*/
private void checkSchedulerHealth() throws SchedulerException {
if (!scheduler.isStarted()) {
log.warn("调度器未启动,手动启动...");
scheduler.start();
}
SchedulerMetaData metaData = scheduler.getMetaData();
// 低版本兼容:获取线程池大小和已执行任务数(替代活跃线程数)
int poolSize = metaData.getThreadPoolSize();
long executedJobs = metaData.getNumberOfJobsExecuted();
log.info("Quartz健康状态:线程池大小={}, 已执行任务数={}", poolSize, executedJobs);
// 线程池大小预警(根据实际需求调整阈值)
if (poolSize < 5) {
log.warn("Quartz线程池过小(当前={}),可能导致任务延迟", poolSize);
}
}
/**
* 检查触发器是否为ERROR状态
*/
private boolean isTriggerError(String jobId) throws SchedulerException {
TriggerKey triggerKey = new TriggerKey(jobId + "_TRIGGER", TRIGGER_GROUP);
if (!scheduler.checkExists(triggerKey)) {
return false;
}
Trigger.TriggerState state = scheduler.getTriggerState(triggerKey);
return state == Trigger.TriggerState.ERROR;
}
/**
* 检查任务是否已存在(避免重复创建)
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment