Commit 18c191c4 authored by wanghao's avatar wanghao

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

parent 1f857407
...@@ -16,10 +16,7 @@ import org.springframework.stereotype.Component; ...@@ -16,10 +16,7 @@ import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List; import java.util.List;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Predicate; import java.util.function.Predicate;
...@@ -41,6 +38,15 @@ public class DeviceStatusReaderAndTimeSetter { ...@@ -41,6 +38,15 @@ public class DeviceStatusReaderAndTimeSetter {
// 工厂 // 工厂
private static final ModbusFactory modbusFactory = new ModbusFactory(); private static final ModbusFactory modbusFactory = new ModbusFactory();
// 1. 关键优化:固定线程池大小(不随设备数变化,根据CPU核数设置,如10)
private static final ExecutorService FIXED_THREAD_POOL = new ThreadPoolExecutor(
5, // 核心线程数(常驻线程)
10, // 最大线程数(峰值线程)
60, // 空闲线程存活时间(60秒)
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100), // 任务队列(缓冲100个任务,避免任务堆积)
new ThreadPoolExecutor.CallerRunsPolicy() // 队列满时,由调用线程执行(避免任务丢失)
);
@Resource @Resource
private ITEquipmentAlarmDataService alarmDataService; private ITEquipmentAlarmDataService alarmDataService;
...@@ -155,11 +161,10 @@ public class DeviceStatusReaderAndTimeSetter { ...@@ -155,11 +161,10 @@ public class DeviceStatusReaderAndTimeSetter {
} }
final CountDownLatch latch = new CountDownLatch(deviceIds.size()); final CountDownLatch latch = new CountDownLatch(deviceIds.size());
ExecutorService executor = Executors.newFixedThreadPool(deviceIds.size());
for (int deviceId : deviceIds) { for (int deviceId : deviceIds) {
final int devId = deviceId; final int devId = deviceId;
executor.submit(() -> { FIXED_THREAD_POOL.submit(() -> {
ModbusMaster threadMaster = null; ModbusMaster threadMaster = null;
try { try {
...@@ -194,17 +199,31 @@ public class DeviceStatusReaderAndTimeSetter { ...@@ -194,17 +199,31 @@ public class DeviceStatusReaderAndTimeSetter {
}); });
} }
executor.shutdown(); // 8. 等待任务完成(优化超时时间,避免长期阻塞)
try { try {
if (!executor.awaitTermination(TIMEOUT_MINUTES, TimeUnit.MINUTES)) { // 超时时间设为30秒(根据设备数调整,确保不超过Job执行周期)
TEquipmentAlarmData alarmData = new TEquipmentAlarmData(); if (!latch.await(30, TimeUnit.SECONDS)) {
alarmData.setfAlarmType("03"); //01.老化柜 02.机械臂 03.老化层 04.点位 log.warn("IP{}: 部分设备监控超时(未完成设备数:{})", ip, latch.getCount());
alarmData.setfEquipmentCode("ip:" + ip + ",port:" + port); recordAlarm("03", "ip:" + ip + ",port:" + port, "部分设备监控超时");
alarmData.setfAlarmData("警告: 部分设备监控任务超时未完成");
alarmDataService.insertTEquipmentAlarmData(alarmData);
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); log.error("IP{}: 监控任务被中断", ip, e);
Thread.currentThread().interrupt(); // 恢复中断状态
}
}
/**
* 统一告警记录(抽离避免重复代码)
*/
private void recordAlarm(String alarmType, String equipmentCode, String alarmData) {
try {
TEquipmentAlarmData alarm = new TEquipmentAlarmData();
alarm.setfAlarmType(alarmType);
alarm.setfEquipmentCode(equipmentCode);
alarm.setfAlarmData(alarmData);
alarm.setfCreateTime(new java.util.Date());
alarmDataService.insertTEquipmentAlarmData(alarm);
} catch (Exception e) {
log.error("告警记录失败:{}", alarmData, e);
} }
} }
} }
...@@ -13,6 +13,9 @@ public class RobotArmMessageParser { ...@@ -13,6 +13,9 @@ public class RobotArmMessageParser {
"PPP (\\w+) (\\S+)(?: (\\d+),(\\d+),(\\d+),(\\d+),)?" "PPP (\\w+) (\\S+)(?: (\\d+),(\\d+),(\\d+),(\\d+),)?"
); );
// 坐标判定的误差范围(-2到2之间)
private static final int COORDINATE_TOLERANCE = 2;
public static RobotArmStatus parseMessage(String message) { public static RobotArmStatus parseMessage(String message) {
Matcher matcher = STATUS_PATTERN.matcher(message); Matcher matcher = STATUS_PATTERN.matcher(message);
if (matcher.find()) { if (matcher.find()) {
...@@ -57,6 +60,43 @@ public class RobotArmMessageParser { ...@@ -57,6 +60,43 @@ public class RobotArmMessageParser {
this.r = r; this.r = r;
} }
/**
* 判断x坐标是否在[-2, 2]范围内(包含边界)
*/
public boolean isXInRange() {
return isCoordInRange(x);
}
/**
* 判断y坐标是否在[-2, 2]范围内(包含边界)
*/
public boolean isYInRange() {
return isCoordInRange(y);
}
/**
* 判断z坐标是否在[-2, 2]范围内(包含边界)
*/
public boolean isZInRange() {
return isCoordInRange(z);
}
/**
* 判断r坐标是否在[-2, 2]范围内(包含边界)
*/
public boolean isRInRange() {
return isCoordInRange(r);
}
/**
* 通用坐标判定:是否在[-2, 2]范围内
* @param coord 坐标值(可能为null)
* @return 若坐标在范围内则返回true,否则返回false(坐标为null时返回false)
*/
private boolean isCoordInRange(Integer coord) {
return coord != null && coord >= -COORDINATE_TOLERANCE && coord <= COORDINATE_TOLERANCE;
}
public boolean isBusy() { public boolean isBusy() {
return "BUSY".equals(code); return "BUSY".equals(code);
} }
...@@ -69,8 +109,15 @@ public class RobotArmMessageParser { ...@@ -69,8 +109,15 @@ public class RobotArmMessageParser {
return isOk() && "完成".equals(text); return isOk() && "完成".equals(text);
} }
/**
* 判断是否完全空闲:状态完成且所有坐标在[-2, 2]范围内
*/
public boolean isFullyIdle() { public boolean isFullyIdle() {
return isComplete() && x == 0 && y == 0 && z == 0 && r == 0; return isComplete()
&& isXInRange()
&& isYInRange()
&& isZInRange()
&& isRInRange();
} }
// Getters // Getters
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
<el-table-column prop="status" label="状态" align="center"> <el-table-column prop="status" label="状态" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag :type="statusTagType(scope.row.fStatus)" v-if="scope.row.fStatus === '1'" class="status-tag">运行中</el-tag> <el-tag :type="statusTagType(scope.row.fStatus)" v-if="scope.row.fStatus === '1'" class="status-tag">运行中</el-tag>
<el-tag :type="statusTagType(scope.row.fStatus)" v-if="scope.row.fStatus === '2'" class="status-tag">质检完成</el-tag> <el-tag :type="statusTagType(scope.row.fStatus)" v-else-if="scope.row.fStatus === '2'" class="status-tag">质检完成</el-tag>
<el-tag :type="statusTagType(scope.row.fStatus)" v-else class="status-tag">空闲</el-tag> <el-tag :type="statusTagType(scope.row.fStatus)" v-else class="status-tag">空闲</el-tag>
</template> </template>
</el-table-column> </el-table-column>
......
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