feat(wms): 优化批次分配逻辑
- 新增死锁检测功能,判断任务执行顺序是否会产生死锁 - 如果存在死锁,使用拓扑排序找出可行的批次分配方案 - 如果不存在死锁,按 processId 合并任务生成批次组 - 优化了代码结构,提高了可读性和可维护性
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
package com.klp.controller;
|
package com.klp.controller;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import com.klp.domain.vo.BatchGroupVo;
|
import com.klp.domain.vo.BatchGroupVo;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -119,8 +121,8 @@ public class WmsBatchController extends BaseController {
|
|||||||
.collect(java.util.stream.Collectors.groupingBy(BatchGroupVo::getProcessId));
|
.collect(java.util.stream.Collectors.groupingBy(BatchGroupVo::getProcessId));
|
||||||
|
|
||||||
// 合并相同processId的批次组
|
// 合并相同processId的批次组
|
||||||
List<BatchGroupVo> mergedBatches = new java.util.ArrayList<>();
|
List<BatchGroupVo> mergedBatches = new ArrayList<>();
|
||||||
java.util.concurrent.atomic.AtomicInteger groupCounter = new java.util.concurrent.atomic.AtomicInteger(1);
|
AtomicInteger groupCounter = new AtomicInteger(1);
|
||||||
|
|
||||||
groupedByProcessId.forEach((processId, groups) -> {
|
groupedByProcessId.forEach((processId, groups) -> {
|
||||||
// 创建一个新的合并后的批次组
|
// 创建一个新的合并后的批次组
|
||||||
|
|||||||
@@ -116,6 +116,79 @@ public class WmsBatchServiceImpl implements IWmsBatchService {
|
|||||||
return baseMapper.deleteBatchIds(ids) > 0;
|
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的任务会合并到一个批次组中
|
* 相同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<>();
|
List<BatchGroupVo> result = new ArrayList<>();
|
||||||
int groupId = 1;
|
int groupId = 1;
|
||||||
for (List<String> group : batchGroups) {
|
for (Map.Entry<String, List<String>> entry : processTasks.entrySet()) {
|
||||||
if (!group.isEmpty()) {
|
String processId = entry.getKey();
|
||||||
String processId = taskToProcess.get(group.get(0));
|
List<String> tasks = entry.getValue();
|
||||||
BatchGroupVo batchGroup = new BatchGroupVo();
|
|
||||||
batchGroup.setGroupId("Group-" + groupId++);
|
BatchGroupVo batchGroup = new BatchGroupVo();
|
||||||
batchGroup.setProcessId(processId);
|
batchGroup.setGroupId("Group-" + groupId++);
|
||||||
batchGroup.setTaskIds(group);
|
batchGroup.setProcessId(processId);
|
||||||
result.add(batchGroup);
|
batchGroup.setTaskIds(tasks);
|
||||||
}
|
result.add(batchGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建任务依赖图
|
* 构建任务依赖图
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user