package com.mes.job;
|
|
import com.mes.entity.PlcAddress;
|
import com.mes.entity.PlcTestTask;
|
import com.mes.service.PlcAddressService;
|
import com.mes.service.PlcTestTaskService;
|
import com.mes.service.PlcTestWriteService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.stereotype.Component;
|
|
import javax.annotation.Resource;
|
import java.util.*;
|
import java.util.concurrent.ConcurrentHashMap;
|
|
/**
|
* PLC自动测试任务调度器
|
* 支持为指定项目创建和管理自动测试任务
|
*
|
* 设计思路:
|
* 1. 维护projectId -> 自动任务配置的映射
|
* 2. 支持动态启动/停止自动测试
|
* 3. 每个项目可独立配置自动测试参数
|
* 4. 在PlcTestController中调用,配合AUTOMATIC模式
|
*
|
* @author huang
|
* @date 2025/11/04
|
*/
|
@Slf4j
|
@Component
|
public class PlcAutoTestTaskScheduler {
|
|
@Resource
|
private PlcTestWriteService plcTestWriteService;
|
|
@Resource
|
private PlcTestTaskService plcTestTaskService;
|
|
@Resource
|
private PlcAddressService plcAddressService;
|
|
/**
|
* 自动任务配置
|
*/
|
public static class AutoTaskConfig {
|
/** 项目ID */
|
public String projectId;
|
/** 模块名称 */
|
public String module;
|
/** 选中的字段 */
|
public List<String> selectedFields;
|
/** 执行间隔(毫秒) */
|
public long intervalMs;
|
/** 请求后到汇报之间的处理延迟时间(毫秒) */
|
public long processDelayMs;
|
/** 最大重试次数 */
|
public int maxRetries;
|
/** 是否启用 */
|
public boolean enabled;
|
/** 运行中的任务线程 */
|
public volatile Thread taskThread;
|
|
public AutoTaskConfig(String projectId, String module, List<String> selectedFields, long intervalMs, long processDelayMs) {
|
this.projectId = projectId;
|
this.module = module;
|
this.selectedFields = selectedFields;
|
this.intervalMs = intervalMs;
|
this.processDelayMs = processDelayMs > 0 ? processDelayMs : 1000; // 默认1秒
|
this.maxRetries = 3;
|
this.enabled = false;
|
this.taskThread = null;
|
}
|
}
|
|
/** projectId -> AutoTaskConfig 的映射 */
|
private final Map<String, AutoTaskConfig> autoTaskConfigs = new ConcurrentHashMap<>();
|
|
/**
|
* 启动自动测试任务
|
*
|
* @param projectId 项目ID
|
* @param module 模块名称
|
* @param selectedFields 选中的字段列表
|
* @param intervalMs 执行间隔(毫秒)
|
* @param processDelayMs 请求后到汇报之间的处理延迟(毫秒)
|
* @return
|
*/
|
public PlcTestTask startAutoTest(String projectId, String module, List<String> selectedFields, long intervalMs, long processDelayMs) {
|
try {
|
// 检查是否已存在该项目的自动任务
|
if (autoTaskConfigs.containsKey(projectId) && autoTaskConfigs.get(projectId).enabled) {
|
log.warn("项目 {} 的自动测试任务已在运行,请先停止", projectId);
|
return null;
|
}
|
|
// 创建或更新配置
|
AutoTaskConfig config = new AutoTaskConfig(projectId, module, selectedFields, intervalMs, processDelayMs);
|
config.enabled = true;
|
|
// 创建并启动任务线程
|
config.taskThread = new Thread(() -> executeAutoTestLoop(config), "AutoTest-" + projectId);
|
config.taskThread.setDaemon(false);
|
config.taskThread.start();
|
|
autoTaskConfigs.put(projectId, config);
|
log.info("启动自动测试任务,projectId: {}, module: {}, interval: {}ms", projectId, module, intervalMs);
|
} catch (Exception e) {
|
log.error("启动自动测试任务失败,projectId: {}", projectId, e);
|
}
|
return null;
|
}
|
|
/**
|
* 停止自动测试任务
|
*
|
* @param projectId 项目ID
|
*/
|
public void stopAutoTest(String projectId) {
|
try {
|
AutoTaskConfig config = autoTaskConfigs.get(projectId);
|
if (config == null) {
|
log.warn("项目 {} 的自动测试任务不存在", projectId);
|
return;
|
}
|
|
config.enabled = false;
|
|
// 中断线程
|
if (config.taskThread != null && config.taskThread.isAlive()) {
|
config.taskThread.interrupt();
|
try {
|
config.taskThread.join(5000); // 等待线程结束,最多5秒
|
} catch (InterruptedException e) {
|
log.warn("等待自动测试任务线程结束时被中断");
|
}
|
}
|
|
autoTaskConfigs.remove(projectId);
|
log.info("停止自动测试任务,projectId: {}", projectId);
|
} catch (Exception e) {
|
log.error("停止自动测试任务失败,projectId: {}", projectId, e);
|
}
|
}
|
|
/**
|
* 检查自动测试任务是否运行中
|
*
|
* @param projectId 项目ID
|
* @return true表示运行中
|
*/
|
public boolean isAutoTestRunning(String projectId) {
|
AutoTaskConfig config = autoTaskConfigs.get(projectId);
|
return config != null && config.enabled;
|
}
|
|
/**
|
* 获取自动任务配置
|
*
|
* @param projectId 项目ID
|
* @return 配置信息
|
*/
|
public AutoTaskConfig getAutoTaskConfig(String projectId) {
|
return autoTaskConfigs.get(projectId);
|
}
|
|
/**
|
* 自动测试循环执行
|
*
|
* @param config 任务配置
|
*/
|
private void executeAutoTestLoop(AutoTaskConfig config) {
|
log.info("自动测试循环已启动,projectId: {}", config.projectId);
|
|
int cycleCount = 0;
|
while (config.enabled && !Thread.currentThread().isInterrupted()) {
|
try {
|
cycleCount++;
|
log.info("执行自动测试循环 #{}, projectId: {}", cycleCount, config.projectId);
|
|
// 获取项目配置
|
PlcAddress plcConfig = plcAddressService.getMappingByProjectId(config.projectId);
|
if (plcConfig == null) {
|
log.error("无法获取项目 {} 的PLC配置", config.projectId);
|
continue;
|
}
|
|
// 创建自动任务记录
|
PlcTestTask task = new PlcTestTask();
|
task.setProjectId(config.projectId);
|
task.setModule(config.module);
|
task.setOperationMode("AUTOMATIC");
|
task.setStatus("RUNNING");
|
task.setStartTime(new Date());
|
if (config.selectedFields != null) {
|
task.setSelectedFields(String.join(",", config.selectedFields));
|
}
|
|
// 保存任务并获取ID
|
PlcTestTask savedTask = plcTestTaskService.createTask(task);
|
if (savedTask == null || savedTask.getId() == null) {
|
log.error("保存任务失败,无法获取任务ID,projectId: {}", config.projectId);
|
continue;
|
}
|
Long id = savedTask.getId();
|
|
// 执行测试步骤
|
long startTime = System.currentTimeMillis();
|
boolean success = true;
|
String errorMessage = null;
|
|
try {
|
// 步骤1:发送PLC请求
|
log.debug("步骤1:发送PLC请求,id: {}", id);
|
boolean requestSuccess = plcTestWriteService.simulatePlcRequest(config.projectId);
|
if (!requestSuccess) {
|
throw new RuntimeException("PLC请求发送失败");
|
}
|
|
// 步骤2:等待MES处理(使用用户配置的延迟时间)
|
log.debug("步骤2:等待MES处理 {}ms", config.processDelayMs);
|
Thread.sleep(config.processDelayMs);
|
|
// 步骤3:汇报完成
|
log.debug("步骤3:汇报完成,id: {}", id);
|
boolean reportSuccess = plcTestWriteService.simulatePlcReport(config.projectId);
|
if (!reportSuccess) {
|
throw new RuntimeException("PLC汇报失败");
|
}
|
|
// 步骤4:确认完成
|
log.debug("步骤4:确认完成,id: {}", id);
|
|
} catch (Exception e) {
|
success = false;
|
errorMessage = e.getMessage();
|
log.error("自动测试执行出错,id: {}", id, e);
|
}
|
|
// 更新任务完成状态
|
long duration = System.currentTimeMillis() - startTime;
|
String finalStatus = success ? "SUCCESS" : "FAILED";
|
plcTestTaskService.completeTask(id, finalStatus, (int) duration,
|
"{\"cycle\": " + cycleCount + "}", errorMessage);
|
|
log.info("自动测试循环 #{} 完成,id: {}, status: {}", cycleCount, id, finalStatus);
|
|
// 等待下一次执行
|
if (config.enabled) {
|
log.debug("等待 {}ms 后执行下一轮", config.intervalMs);
|
Thread.sleep(config.intervalMs);
|
}
|
|
} catch (InterruptedException e) {
|
log.info("自动测试循环被中断,projectId: {}", config.projectId);
|
Thread.currentThread().interrupt();
|
break;
|
} catch (Exception e) {
|
log.error("自动测试循环执行异常,projectId: {}", config.projectId, e);
|
try {
|
Thread.sleep(config.intervalMs);
|
} catch (InterruptedException ie) {
|
log.info("自动测试循环被中断");
|
break;
|
}
|
}
|
}
|
|
log.info("自动测试循环已结束,projectId: {}, 共执行 {} 轮", config.projectId, cycleCount);
|
}
|
|
/**
|
* 停止所有运行中的自动测试任务
|
*/
|
public void stopAllAutoTests() {
|
List<String> projectIds = new ArrayList<>(autoTaskConfigs.keySet());
|
for (String projectId : projectIds) {
|
stopAutoTest(projectId);
|
}
|
log.info("已停止所有自动测试任务");
|
}
|
|
/**
|
* 获取所有运行中的自动任务
|
*
|
* @return projectId列表
|
*/
|
public List<String> getRunningAutoTests() {
|
List<String> result = new ArrayList<>();
|
for (Map.Entry<String, AutoTaskConfig> entry : autoTaskConfigs.entrySet()) {
|
if (entry.getValue().enabled) {
|
result.add(entry.getKey());
|
}
|
}
|
return result;
|
}
|
}
|