| | |
| | | resolvedPolicy == null ? null : resolvedPolicy.getDefaultProfileCode(), |
| | | elapsedMillis(totalStartNs)); |
| | | StationPathRuntimeSnapshot runtimeSnapshot = loadStationPathRuntimeSnapshot(currentTaskNo); |
| | | List<NavigateNode> shortFallbackPath = buildRerouteShortFallbackPath( |
| | | startStationId, |
| | | endStationId, |
| | | currentTaskNo, |
| | | resolvedPolicy, |
| | | runtimeSnapshot |
| | | ); |
| | | StationPathSearchContext context = buildStationPathSearchContext( |
| | | startStationId, |
| | | endStationId, |
| | |
| | | runtimeSnapshot |
| | | ); |
| | | if (context.allList.isEmpty()) { |
| | | log.warn("站点路径候选计算结束,原因=empty_search_context,startStationId={},endStationId={},taskNo={},totalCostMs={}", |
| | | startStationId, endStationId, currentTaskNo, elapsedMillis(totalStartNs)); |
| | | return new ArrayList<>(); |
| | | List<List<NavigateNode>> fallbackCandidateList = normalizeCandidatePaths(Collections.singletonList(shortFallbackPath)); |
| | | log.warn("站点路径候选计算结束,原因=empty_search_context,startStationId={},endStationId={},taskNo={},fallbackCandidateCount={},fallbackPath={},totalCostMs={}", |
| | | startStationId, |
| | | endStationId, |
| | | currentTaskNo, |
| | | fallbackCandidateList.size(), |
| | | JSON.toJSONString(extractStationIdList(shortFallbackPath)), |
| | | elapsedMillis(totalStartNs)); |
| | | return fallbackCandidateList; |
| | | } |
| | | |
| | | long orderStartNs = System.nanoTime(); |
| | |
| | | endStationId, |
| | | runtimeSnapshot |
| | | ); |
| | | List<List<NavigateNode>> normalizedPathList = normalizeCandidatePaths(orderedPathList); |
| | | log.info("站点路径候选计算结束,startStationId={},endStationId={},taskNo={},rawCandidateCount={},orderedPathCount={},normalizedPathCount={},orderCostMs={},totalCostMs={}", |
| | | List<List<NavigateNode>> candidatePathList = appendShortFallbackCandidate(orderedPathList, shortFallbackPath); |
| | | List<List<NavigateNode>> normalizedPathList = normalizeCandidatePaths(candidatePathList); |
| | | log.info("站点路径候选计算结束,startStationId={},endStationId={},taskNo={},rawCandidateCount={},orderedPathCount={},fallbackPathLen={},normalizedPathCount={},orderCostMs={},totalCostMs={}", |
| | | startStationId, |
| | | endStationId, |
| | | currentTaskNo, |
| | | context.allList.size(), |
| | | orderedPathList == null ? null : orderedPathList.size(), |
| | | shortFallbackPath == null ? 0 : shortFallbackPath.size(), |
| | | normalizedPathList.size(), |
| | | elapsedMillis(orderStartNs), |
| | | elapsedMillis(totalStartNs)); |
| | |
| | | return DirectPathSearchResult.empty(includeWaypoint, includeSoftPreference); |
| | | } |
| | | |
| | | private List<NavigateNode> buildRerouteShortFallbackPath(Integer startStationId, |
| | | Integer endStationId, |
| | | Integer currentTaskNo, |
| | | StationPathResolvedPolicy resolvedPolicy, |
| | | StationPathRuntimeSnapshot runtimeSnapshot) { |
| | | long startNs = System.nanoTime(); |
| | | try { |
| | | List<NavigateNode> path = findStationDirectPath( |
| | | startStationId, |
| | | endStationId, |
| | | currentTaskNo, |
| | | 0.0d, |
| | | StationPathCalcMode.OPTIMAL, |
| | | resolvedPolicy, |
| | | runtimeSnapshot |
| | | ); |
| | | List<NavigateNode> normalizedPath = normalizeStationPath(path); |
| | | log.info("站点路径堵塞重规划短路径保底计算完成,startStationId={},endStationId={},taskNo={},pathLen={},path={},costMs={}", |
| | | startStationId, |
| | | endStationId, |
| | | currentTaskNo, |
| | | normalizedPath.size(), |
| | | JSON.toJSONString(extractStationIdList(normalizedPath)), |
| | | elapsedMillis(startNs)); |
| | | return normalizedPath; |
| | | } catch (Exception e) { |
| | | log.warn("站点路径堵塞重规划短路径保底计算失败,startStationId={},endStationId={},taskNo={},costMs={},error={}", |
| | | startStationId, |
| | | endStationId, |
| | | currentTaskNo, |
| | | elapsedMillis(startNs), |
| | | e.toString()); |
| | | return new ArrayList<>(); |
| | | } |
| | | } |
| | | |
| | | private List<List<NavigateNode>> appendShortFallbackCandidate(List<List<NavigateNode>> orderedPathList, |
| | | List<NavigateNode> shortFallbackPath) { |
| | | List<List<NavigateNode>> candidatePathList = new ArrayList<>(); |
| | | if (orderedPathList != null && !orderedPathList.isEmpty()) { |
| | | candidatePathList.addAll(orderedPathList); |
| | | } |
| | | if (shortFallbackPath != null && !shortFallbackPath.isEmpty()) { |
| | | candidatePathList.add(shortFallbackPath); |
| | | } |
| | | return candidatePathList; |
| | | } |
| | | |
| | | private List<NavigateNode> searchDirectPath(DirectStationPathContext context, |
| | | boolean includeWaypoint, |
| | | boolean includeSoftPreference) { |
| | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.core.common.Cools; |
| | | import com.zy.common.utils.RedisUtil; |
| | | import com.zy.core.News; |
| | | import com.zy.core.enums.RedisKeyType; |
| | | import com.zy.core.model.command.StationCommand; |
| | | import com.zy.core.service.StationTaskLoopService; |
| | |
| | | |
| | | private static final int RUN_BLOCK_REROUTE_STATE_EXPIRE_SECONDS = 60 * 60 * 24; |
| | | private static final int SHORT_PATH_REPEAT_AVOID_THRESHOLD = 2; |
| | | private static final int PLANNER_RESET_PLAN_COUNT_THRESHOLD = 20; |
| | | |
| | | private final RedisUtil redisUtil; |
| | | |
| | |
| | | rerouteState.setTaskNo(taskNo); |
| | | rerouteState.setBlockStationId(blockStationId); |
| | | rerouteState.setPlanCount((rerouteState.getPlanCount() == null ? 0 : rerouteState.getPlanCount()) + 1); |
| | | int currentPlanCount = rerouteState.getPlanCount() == null ? 0 : rerouteState.getPlanCount(); |
| | | boolean resetForPlanCountLimit = rerouteState.getPlanCount() > PLANNER_RESET_PLAN_COUNT_THRESHOLD; |
| | | if (resetForPlanCountLimit) { |
| | | rerouteState.resetPlanner(); |
| | | rerouteState.setTaskNo(taskNo); |
| | | rerouteState.setBlockStationId(blockStationId); |
| | | rerouteState.setPlanCount(1); |
| | | News.info("输送线堵塞重规划planner累计超过阈值,已清空路线记忆并从最短路线重新选择,taskNo={},blockStationId={},planCount={},threshold={}", |
| | | taskNo, |
| | | blockStationId, |
| | | currentPlanCount, |
| | | PLANNER_RESET_PLAN_COUNT_THRESHOLD); |
| | | } |
| | | |
| | | StationCommand rerouteCommand = selectAvailableRerouteCommand(rerouteState, loopEvaluation, candidateCommands); |
| | | StationCommand rerouteCommand = selectAvailableRerouteCommand( |
| | | rerouteState, |
| | | loopEvaluation, |
| | | candidateCommands, |
| | | resetForPlanCountLimit |
| | | ); |
| | | if (rerouteCommand == null && candidateCommands != null && !candidateCommands.isEmpty()) { |
| | | rerouteState.resetIssuedRoutes(); |
| | | rerouteCommand = selectAvailableRerouteCommand(rerouteState, loopEvaluation, candidateCommands); |
| | | rerouteCommand = selectAvailableRerouteCommand( |
| | | rerouteState, |
| | | loopEvaluation, |
| | | candidateCommands, |
| | | resetForPlanCountLimit |
| | | ); |
| | | } |
| | | |
| | | saveRunBlockRerouteState(rerouteState); |
| | |
| | | |
| | | private StationCommand selectAvailableRerouteCommand(RunBlockRerouteState rerouteState, |
| | | StationTaskLoopService.LoopEvaluation loopEvaluation, |
| | | List<StationCommand> candidateCommands) { |
| | | List<StationCommand> candidateCommands, |
| | | boolean preferShortestPath) { |
| | | if (rerouteState == null || candidateCommands == null || candidateCommands.isEmpty()) { |
| | | return null; |
| | | } |
| | |
| | | return null; |
| | | } |
| | | |
| | | List<RerouteCandidateCommand> orderedCandidateCommandList = reorderCandidateCommandsForLoopRelease(candidateCommandList); |
| | | List<RerouteCandidateCommand> orderedCandidateCommandList = preferShortestPath |
| | | ? reorderCandidateCommandsByShortestPath(candidateCommandList) |
| | | : reorderCandidateCommandsForLoopRelease(candidateCommandList); |
| | | for (RerouteCandidateCommand candidateCommand : orderedCandidateCommandList) { |
| | | if (candidateCommand == null || candidateCommand.getCommand() == null) { |
| | | continue; |
| | |
| | | return rerouteCommand; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private List<RerouteCandidateCommand> reorderCandidateCommandsByShortestPath(List<RerouteCandidateCommand> candidateCommandList) { |
| | | if (candidateCommandList == null || candidateCommandList.isEmpty()) { |
| | | return new ArrayList<>(); |
| | | } |
| | | List<RerouteCandidateCommand> reorderedList = new ArrayList<>(candidateCommandList); |
| | | reorderedList.sort((left, right) -> { |
| | | int leftPathLength = left == null || left.getPathLength() == null ? Integer.MAX_VALUE : left.getPathLength(); |
| | | int rightPathLength = right == null || right.getPathLength() == null ? Integer.MAX_VALUE : right.getPathLength(); |
| | | return Integer.compare(leftPathLength, rightPathLength); |
| | | }); |
| | | return reorderedList; |
| | | } |
| | | |
| | | private List<RerouteCandidateCommand> reorderCandidateCommandsForLoopRelease(List<RerouteCandidateCommand> candidateCommandList) { |
| | |
| | | this.issuedRouteSignatureSet = new LinkedHashSet<>(); |
| | | } |
| | | |
| | | private void resetPlanner() { |
| | | resetIssuedRoutes(); |
| | | this.routeIssueCountMap = new HashMap<>(); |
| | | } |
| | | |
| | | private static String buildPathSignatureText(List<Integer> routePath) { |
| | | if (routePath == null || routePath.isEmpty()) { |
| | | return ""; |