From 1aee9a5f65488c740c0d882537b4778974fe03f9 Mon Sep 17 00:00:00 2001 From: Joshi <3040996759@qq.com> Date: Thu, 14 Aug 2025 17:59:32 +0800 Subject: [PATCH] =?UTF-8?q?feat(wms):=20=E4=BC=98=E5=8C=96=E6=89=B9?= =?UTF-8?q?=E6=AC=A1=E5=88=86=E9=85=8D=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增死锁检测功能,判断任务执行顺序是否会产生死锁 - 如果存在死锁,使用拓扑排序找出可行的批次分配方案 - 如果不存在死锁,按 processId 合并任务生成批次组 - 优化了代码结构,提高了可读性和可维护性 --- .../klp/controller/WmsBatchController.java | 6 +- .../klp/service/impl/WmsBatchServiceImpl.java | 133 ++++++++++++++++-- 2 files changed, 124 insertions(+), 15 deletions(-) diff --git a/klp-wms/src/main/java/com/klp/controller/WmsBatchController.java b/klp-wms/src/main/java/com/klp/controller/WmsBatchController.java index 901134a6..8b6cfc36 100644 --- a/klp-wms/src/main/java/com/klp/controller/WmsBatchController.java +++ b/klp-wms/src/main/java/com/klp/controller/WmsBatchController.java @@ -1,8 +1,10 @@ package com.klp.controller; +import java.util.ArrayList; import java.util.List; import java.util.Arrays; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import com.klp.domain.vo.BatchGroupVo; import lombok.RequiredArgsConstructor; @@ -119,8 +121,8 @@ public class WmsBatchController extends BaseController { .collect(java.util.stream.Collectors.groupingBy(BatchGroupVo::getProcessId)); // 合并相同processId的批次组 - List mergedBatches = new java.util.ArrayList<>(); - java.util.concurrent.atomic.AtomicInteger groupCounter = new java.util.concurrent.atomic.AtomicInteger(1); + List mergedBatches = new ArrayList<>(); + AtomicInteger groupCounter = new AtomicInteger(1); groupedByProcessId.forEach((processId, groups) -> { // 创建一个新的合并后的批次组 diff --git a/klp-wms/src/main/java/com/klp/service/impl/WmsBatchServiceImpl.java b/klp-wms/src/main/java/com/klp/service/impl/WmsBatchServiceImpl.java index 2d2b803c..073ba8c8 100644 --- a/klp-wms/src/main/java/com/klp/service/impl/WmsBatchServiceImpl.java +++ b/klp-wms/src/main/java/com/klp/service/impl/WmsBatchServiceImpl.java @@ -116,6 +116,79 @@ public class WmsBatchServiceImpl implements IWmsBatchService { return baseMapper.deleteBatchIds(ids) > 0; } + /** + * 检测任务执行是否会产生死锁 + * + * @param rows 任务执行顺序数组 + * @return 是否存在死锁 + */ + public boolean checkDeadlock(List>> rows) { + // 保存任务执行顺序数组 + this.rows = rows; + + // 构建任务依赖图 + Map> taskGraph = buildTaskDependencyGraph(rows); + + // 获取所有任务 + Set allTasks = new HashSet<>(); + for (List> row : rows) { + for (Map task : row) { + allTasks.add(task.get("taskId").toString()); + } + } + + // 使用DFS检测是否存在环(死锁) + Map visited = new HashMap<>(); + for (String task : allTasks) { + if (visited.getOrDefault(task, 0) == 0) { + if (hasCycleDFS(task, taskGraph, visited)) { + return true; // 存在死锁 + } + } + } + + return false; // 不存在死锁 + } + + /** + * 构建进程依赖图 + * 如果进程A的任务必须在进程B的任务之前执行,则进程B依赖于进程A + */ + private Map> buildProcessDependencyGraph(List>> rows) { + Map> processGraph = new HashMap<>(); + Map> taskGraph = buildTaskDependencyGraph(rows); + + // 获取任务与进程的映射关系 + Map taskToProcess = new HashMap<>(); + for (List> row : rows) { + for (Map task : row) { + String taskId = task.get("taskId").toString(); + String processId = task.get("processId").toString(); + taskToProcess.put(taskId, processId); + } + } + + // 根据任务依赖关系构建进程依赖关系 + for (Map.Entry> entry : taskGraph.entrySet()) { + String taskId = entry.getKey(); + Set dependencies = entry.getValue(); + + String processId = taskToProcess.get(taskId); + + for (String depTaskId : dependencies) { + String depProcessId = taskToProcess.get(depTaskId); + + // 如果依赖的是不同进程的任务,则建立进程间依赖 + if (!processId.equals(depProcessId)) { + processGraph.putIfAbsent(processId, new HashSet<>()); + processGraph.get(processId).add(depProcessId); + } + } + } + + return processGraph; + } + /** * 生成不会产生死锁的批次分配方案 * 相同processId的任务会合并到一个批次组中 @@ -156,27 +229,61 @@ public class WmsBatchServiceImpl implements IWmsBatchService { } } - // 使用拓扑排序找出可行的批次分配方案 - List> batchGroups = generateBatchGroups(taskGraph, allTasks, taskToProcess); + // 检查是否存在死锁 + boolean hasDeadlock = checkDeadlock(rows); + if (hasDeadlock) { + // 如果存在死锁,使用拓扑排序找出可行的批次分配方案 + List> batchGroups = generateBatchGroups(taskGraph, allTasks, taskToProcess); - // 将批次转换为BatchGroupVo格式 + // 将批次转换为BatchGroupVo格式 + List result = new ArrayList<>(); + int groupId = 1; + for (List group : batchGroups) { + if (!group.isEmpty()) { + String processId = taskToProcess.get(group.get(0)); + BatchGroupVo batchGroup = new BatchGroupVo(); + batchGroup.setGroupId("Group-" + groupId++); + batchGroup.setProcessId(processId); + batchGroup.setTaskIds(group); + result.add(batchGroup); + } + } + + return result; + } else { + // 如果不存在死锁,按processId合并任务 + return mergeTasksByProcessId(allTasks, taskToProcess); + } + } + + /** + * 按processId合并任务 + */ + private List mergeTasksByProcessId(Set allTasks, Map taskToProcess) { + // 按processId分组任务 + Map> processTasks = new HashMap<>(); + for (String taskId : allTasks) { + String processId = taskToProcess.get(taskId); + processTasks.computeIfAbsent(processId, k -> new ArrayList<>()).add(taskId); + } + + // 创建批次组 List result = new ArrayList<>(); int groupId = 1; - for (List group : batchGroups) { - if (!group.isEmpty()) { - String processId = taskToProcess.get(group.get(0)); - BatchGroupVo batchGroup = new BatchGroupVo(); - batchGroup.setGroupId("Group-" + groupId++); - batchGroup.setProcessId(processId); - batchGroup.setTaskIds(group); - result.add(batchGroup); - } + for (Map.Entry> entry : processTasks.entrySet()) { + String processId = entry.getKey(); + List tasks = entry.getValue(); + + BatchGroupVo batchGroup = new BatchGroupVo(); + batchGroup.setGroupId("Group-" + groupId++); + batchGroup.setProcessId(processId); + batchGroup.setTaskIds(tasks); + result.add(batchGroup); } return result; } - /** * 构建任务依赖图 */