feat(wms): 优化批次分配逻辑

- 新增死锁检测功能,判断任务执行顺序是否会产生死锁
- 如果存在死锁,使用拓扑排序找出可行的批次分配方案
- 如果不存在死锁,按 processId 合并任务生成批次组
- 优化了代码结构,提高了可读性和可维护性
This commit is contained in:
2025-08-14 17:59:32 +08:00
parent 96da503d0a
commit 1aee9a5f65
2 changed files with 124 additions and 15 deletions

View File

@@ -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<BatchGroupVo> mergedBatches = new java.util.ArrayList<>();
java.util.concurrent.atomic.AtomicInteger groupCounter = new java.util.concurrent.atomic.AtomicInteger(1);
List<BatchGroupVo> mergedBatches = new ArrayList<>();
AtomicInteger groupCounter = new AtomicInteger(1);
groupedByProcessId.forEach((processId, groups) -> {
// 创建一个新的合并后的批次组

View File

@@ -116,6 +116,79 @@ public class WmsBatchServiceImpl implements IWmsBatchService {
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 检测任务执行是否会产生死锁
*
* @param rows 任务执行顺序数组
* @return 是否存在死锁
*/
public boolean checkDeadlock(List<List<Map<String, Object>>> rows) {
// 保存任务执行顺序数组
this.rows = rows;
// 构建任务依赖图
Map<String, Set<String>> taskGraph = buildTaskDependencyGraph(rows);
// 获取所有任务
Set<String> allTasks = new HashSet<>();
for (List<Map<String, Object>> row : rows) {
for (Map<String, Object> task : row) {
allTasks.add(task.get("taskId").toString());
}
}
// 使用DFS检测是否存在环死锁
Map<String, Integer> 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<String, Set<String>> buildProcessDependencyGraph(List<List<Map<String, Object>>> rows) {
Map<String, Set<String>> processGraph = new HashMap<>();
Map<String, Set<String>> taskGraph = buildTaskDependencyGraph(rows);
// 获取任务与进程的映射关系
Map<String, String> taskToProcess = new HashMap<>();
for (List<Map<String, Object>> row : rows) {
for (Map<String, Object> task : row) {
String taskId = task.get("taskId").toString();
String processId = task.get("processId").toString();
taskToProcess.put(taskId, processId);
}
}
// 根据任务依赖关系构建进程依赖关系
for (Map.Entry<String, Set<String>> entry : taskGraph.entrySet()) {
String taskId = entry.getKey();
Set<String> 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<List<String>> batchGroups = generateBatchGroups(taskGraph, allTasks, taskToProcess);
// 检查是否存在死锁
boolean hasDeadlock = checkDeadlock(rows);
if (hasDeadlock) {
// 如果存在死锁,使用拓扑排序找出可行的批次分配方案
List<List<String>> batchGroups = generateBatchGroups(taskGraph, allTasks, taskToProcess);
// 将批次转换为BatchGroupVo格式
// 将批次转换为BatchGroupVo格式
List<BatchGroupVo> result = new ArrayList<>();
int groupId = 1;
for (List<String> 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<BatchGroupVo> mergeTasksByProcessId(Set<String> allTasks, Map<String, String> taskToProcess) {
// 按processId分组任务
Map<String, List<String>> processTasks = new HashMap<>();
for (String taskId : allTasks) {
String processId = taskToProcess.get(taskId);
processTasks.computeIfAbsent(processId, k -> new ArrayList<>()).add(taskId);
}
// 创建批次组
List<BatchGroupVo> result = new ArrayList<>();
int groupId = 1;
for (List<String> 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<String, List<String>> entry : processTasks.entrySet()) {
String processId = entry.getKey();
List<String> tasks = entry.getValue();
BatchGroupVo batchGroup = new BatchGroupVo();
batchGroup.setGroupId("Group-" + groupId++);
batchGroup.setProcessId(processId);
batchGroup.setTaskIds(tasks);
result.add(batchGroup);
}
return result;
}
/**
* 构建任务依赖图
*/