| | |
| | | import com.mes.task.model.TaskExecutionResult; |
| | | import com.mes.task.service.MultiDeviceTaskService; |
| | | import com.mes.task.service.TaskExecutionEngine; |
| | | import lombok.RequiredArgsConstructor; |
| | | import com.mes.task.service.TaskStatusNotificationService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.scheduling.annotation.Async; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.CollectionUtils; |
| | |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.Locale; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 多设备任务服务实现 |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class MultiDeviceTaskServiceImpl extends ServiceImpl<MultiDeviceTaskMapper, MultiDeviceTask> |
| | | implements MultiDeviceTaskService { |
| | | |
| | |
| | | private final DeviceGroupRelationMapper deviceGroupRelationMapper; |
| | | private final TaskStepDetailMapper taskStepDetailMapper; |
| | | private final TaskExecutionEngine taskExecutionEngine; |
| | | private final TaskStatusNotificationService notificationService; |
| | | private final ObjectMapper objectMapper; |
| | | |
| | | public MultiDeviceTaskServiceImpl( |
| | | DeviceGroupConfigService deviceGroupConfigService, |
| | | DeviceGroupRelationMapper deviceGroupRelationMapper, |
| | | TaskStepDetailMapper taskStepDetailMapper, |
| | | TaskExecutionEngine taskExecutionEngine, |
| | | TaskStatusNotificationService notificationService, |
| | | ObjectMapper objectMapper) { |
| | | this.deviceGroupConfigService = deviceGroupConfigService; |
| | | this.deviceGroupRelationMapper = deviceGroupRelationMapper; |
| | | this.taskStepDetailMapper = taskStepDetailMapper; |
| | | this.taskExecutionEngine = taskExecutionEngine; |
| | | this.notificationService = notificationService; |
| | | this.objectMapper = objectMapper; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | } |
| | | |
| | | TaskParameters parameters = request.getParameters(); |
| | | if (parameters == null || CollectionUtils.isEmpty(parameters.getGlassIds())) { |
| | | throw new IllegalArgumentException("至少需要配置一条玻璃ID"); |
| | | if (parameters == null) { |
| | | parameters = new TaskParameters(); |
| | | } |
| | | |
| | | // 默认允许卧转立扫码设备在任务执行阶段获取玻璃信息 |
| | | boolean hasGlassIds = !CollectionUtils.isEmpty(parameters.getGlassIds()); |
| | | if (!hasGlassIds) { |
| | | log.info("测试任务未提供玻璃ID,将在设备组流程中由卧转立扫码设备采集玻璃信息: groupId={}", |
| | | groupConfig.getId()); |
| | | } |
| | | |
| | | // 创建任务记录 |
| | | MultiDeviceTask task = new MultiDeviceTask(); |
| | | task.setTaskId(generateTaskId(groupConfig)); |
| | | task.setGroupId(String.valueOf(groupConfig.getId())); |
| | |
| | | task.setStartTime(new Date()); |
| | | save(task); |
| | | |
| | | // 异步执行任务,立即返回任务ID |
| | | executeTaskAsync(task, groupConfig, devices, parameters); |
| | | |
| | | log.info("设备组任务已启动(异步执行): taskId={}, groupId={}, groupName={}", |
| | | task.getTaskId(), groupConfig.getId(), groupConfig.getGroupName()); |
| | | |
| | | return task; |
| | | } |
| | | |
| | | /** |
| | | * 异步执行设备组任务 |
| | | * 每个设备组作为独立线程执行,互不阻塞 |
| | | */ |
| | | @Async("deviceGroupTaskExecutor") |
| | | public void executeTaskAsync(MultiDeviceTask task, |
| | | DeviceGroupConfig groupConfig, |
| | | List<DeviceConfig> devices, |
| | | TaskParameters parameters) { |
| | | try { |
| | | log.info("开始执行设备组任务: taskId={}, groupId={}, deviceCount={}", |
| | | task.getTaskId(), groupConfig.getId(), devices.size()); |
| | | |
| | | // 更新任务状态为运行中 |
| | | task.setStatus(MultiDeviceTask.Status.RUNNING.name()); |
| | | updateById(task); |
| | | |
| | | // 通知任务开始 |
| | | notificationService.notifyTaskStatus(task); |
| | | |
| | | // 执行任务 |
| | | TaskExecutionResult result = taskExecutionEngine.execute(task, groupConfig, devices, parameters); |
| | | |
| | | // 检查任务数据中是否包含持续运行的标记 |
| | | Map<String, Object> resultData = result.getData(); |
| | | boolean isContinuousTask = resultData != null && "任务已启动,定时器在后台运行中".equals(resultData.get("message")); |
| | | |
| | | // 如果是持续运行的任务(定时器模式),保持 RUNNING 状态,不更新为 COMPLETED |
| | | if (isContinuousTask && result.isSuccess()) { |
| | | log.info("任务已启动定时器,保持运行状态: taskId={}, message={}", |
| | | task.getTaskId(), resultData.get("message")); |
| | | task.setResultData(writeJson(resultData)); |
| | | updateById(task); |
| | | // 通知任务状态(保持 RUNNING) |
| | | notificationService.notifyTaskStatus(task); |
| | | return; |
| | | } |
| | | |
| | | // 更新任务结果(非持续运行的任务) |
| | | task.setStatus(result.isSuccess() ? MultiDeviceTask.Status.COMPLETED.name() : MultiDeviceTask.Status.FAILED.name()); |
| | | task.setErrorMessage(result.isSuccess() ? null : result.getMessage()); |
| | | task.setEndTime(new Date()); |
| | | task.setResultData(writeJson(result.getData())); |
| | | task.setResultData(writeJson(resultData)); |
| | | updateById(task); |
| | | return task; |
| | | |
| | | // 通知任务完成 |
| | | notificationService.notifyTaskStatus(task); |
| | | |
| | | log.info("设备组任务执行完成: taskId={}, success={}, message={}", |
| | | task.getTaskId(), result.isSuccess(), result.getMessage()); |
| | | |
| | | } catch (Exception ex) { |
| | | log.error("多设备任务执行异常, taskId={}", task.getTaskId(), ex); |
| | | log.error("设备组任务执行异常: taskId={}, groupId={}", task.getTaskId(), groupConfig.getId(), ex); |
| | | |
| | | // 更新任务状态为失败 |
| | | task.setStatus(MultiDeviceTask.Status.FAILED.name()); |
| | | task.setErrorMessage(ex.getMessage()); |
| | | task.setEndTime(new Date()); |
| | | updateById(task); |
| | | throw new RuntimeException("多设备任务执行失败: " + ex.getMessage(), ex); |
| | | |
| | | // 通知任务失败 |
| | | notificationService.notifyTaskStatus(task); |
| | | } |
| | | } |
| | | |
| | |
| | | if (task == null) { |
| | | return false; |
| | | } |
| | | if (!MultiDeviceTask.Status.RUNNING.name().equals(task.getStatus())) { |
| | | // 允许在 RUNNING 或 FAILED 状态下执行取消操作 |
| | | String status = task.getStatus(); |
| | | boolean cancellable = MultiDeviceTask.Status.RUNNING.name().equals(status) |
| | | || MultiDeviceTask.Status.FAILED.name().equals(status); |
| | | if (!cancellable) { |
| | | return false; |
| | | } |
| | | // 标记任务取消并停止所有定时器 |
| | | taskExecutionEngine.requestTaskCancellation(taskId); |
| | | task.setStatus(MultiDeviceTask.Status.CANCELLED.name()); |
| | | task.setEndTime(new Date()); |
| | | return updateById(task); |
| | | boolean updated = updateById(task); |
| | | if (updated) { |
| | | notificationService.notifyTaskStatus(task); |
| | | } |
| | | return updated; |
| | | } |
| | | |
| | | @Override |