feat(wms): 优化批次分配逻辑
- 新增死锁检测功能,判断任务执行顺序是否会产生死锁 - 如果存在死锁,使用拓扑排序找出可行的批次分配方案 - 如果不存在死锁,按 processId 合并任务生成批次组 - 优化了代码结构,提高了可读性和可维护性
This commit is contained in:
@@ -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) -> {
|
||||
// 创建一个新的合并后的批次组
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构建任务依赖图
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user