huang
2025-12-02 628aa6a42e587e9f337e213f87f922fc2ab2af02
mes-processes/mes-plcSend/src/main/java/com/mes/task/service/impl/MultiDeviceTaskServiceImpl.java
@@ -19,8 +19,9 @@
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;
@@ -30,13 +31,13 @@
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 {
@@ -44,7 +45,23 @@
    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)
@@ -63,10 +80,18 @@
        }
        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()));
@@ -77,21 +102,77 @@
        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);
        }
    }
@@ -116,12 +197,22 @@
        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