Junjie
2026-04-13 045ee53a62cd7866c1395961076426e9c8782b26
src/main/java/com/zy/core/utils/station/StationRerouteProcessor.java
@@ -50,8 +50,6 @@
@Component
public class StationRerouteProcessor {
    private static final int OUT_ORDER_DISPATCH_LIMIT_SECONDS = 2;
    private static final int STATION_IDLE_RECOVER_SECONDS = 10;
    private static final int STATION_IDLE_RECOVER_LIMIT_SECONDS = 30;
    private static final long STATION_MOVE_RESET_WAIT_MS = 1000L;
    @Autowired
@@ -75,178 +73,127 @@
    @Autowired
    private StationDispatchRuntimeStateSupport stationDispatchRuntimeStateSupport;
    public void checkStationRunBlock() {
    public void checkStationRunBlock(BasDevp basDevp, Integer stationId) {
        try {
            List<BasDevp> basDevps = basDevpService.list(new QueryWrapper<>());
            for (BasDevp basDevp : basDevps) {
                StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo());
                if (stationThread == null) {
                    continue;
                }
                List<Integer> runBlockReassignLocStationList = new ArrayList<>();
                for (StationObjModel stationObjModel : basDevp.getRunBlockReassignLocStationList$()) {
                    runBlockReassignLocStationList.add(stationObjModel.getStationId());
                }
                List<Integer> outOrderStationIds = basDevp.getOutOrderIntList();
                for (StationProtocol stationProtocol : stationThread.getStatus()) {
                    if (stationProtocol.isAutoing()
                            && stationProtocol.isLoading()
                            && stationProtocol.getTaskNo() > 0
                            && stationProtocol.isRunBlock()) {
                        WrkMast wrkMast = wrkMastService.selectByWorkNo(stationProtocol.getTaskNo());
                        if (wrkMast == null) {
                            News.info("输送站点号={} 运行阻塞,但无法找到对应任务,工作号={}", stationProtocol.getStationId(), stationProtocol.getTaskNo());
                            continue;
                        }
                        Object lock = redisUtil.get(RedisKeyType.CHECK_STATION_RUN_BLOCK_LIMIT_.key + stationProtocol.getTaskNo());
                        if (lock != null) {
                            continue;
                        }
                        redisUtil.set(RedisKeyType.CHECK_STATION_RUN_BLOCK_LIMIT_.key + stationProtocol.getTaskNo(), "lock", 15);
                        if (shouldUseRunBlockDirectReassign(wrkMast, stationProtocol.getStationId(), runBlockReassignLocStationList)) {
                            executeRunBlockDirectReassign(basDevp, stationThread, stationProtocol, wrkMast);
                            continue;
                        }
                        Double pathLenFactor = stationOutboundDecisionSupport.resolveOutboundPathLenFactor(wrkMast);
                        RerouteContext context = RerouteContext.create(
                                RerouteSceneType.RUN_BLOCK_REROUTE,
                                basDevp,
                                stationThread,
                                stationProtocol,
                                wrkMast,
                                outOrderStationIds,
                                pathLenFactor,
                                "checkStationRunBlock_reroute"
                        ).withRunBlockCommand()
                                .withSuppressDispatchGuard()
                                .withCancelSessionBeforeDispatch()
                                .withResetSegmentCommandsBeforeDispatch();
                        executeSharedReroute(context);
                    }
                }
            if (basDevp == null || basDevp.getDevpNo() == null || stationId == null) {
                return;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void checkStationIdleRecover() {
        try {
            List<BasDevp> basDevps = basDevpService.list(new QueryWrapper<>());
            for (BasDevp basDevp : basDevps) {
                StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo());
                if (stationThread == null) {
                    continue;
                }
                for (StationProtocol stationProtocol : stationThread.getStatus()) {
                    if (stationProtocol.isAutoing()
                            && stationProtocol.isLoading()
                            && stationProtocol.getTaskNo() > 0
                            && !stationProtocol.isRunBlock()) {
                        checkStationIdleRecover(basDevp, stationThread, stationProtocol, basDevp.getOutOrderIntList());
                    }
                }
            if (shouldSkipRunBlockStation(basDevp, stationId)) {
                return;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void checkStationOutOrder() {
        List<BasDevp> basDevps = basDevpService.list(new QueryWrapper<BasDevp>());
        for (BasDevp basDevp : basDevps) {
            StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo());
            if (stationThread == null) {
                continue;
                return;
            }
            Map<Integer, StationProtocol> statusMap = stationThread.getStatusMap();
            StationProtocol stationProtocol = statusMap == null ? null : statusMap.get(stationId);
            if (stationProtocol == null
                    || !stationProtocol.isAutoing()
                    || !stationProtocol.isLoading()
                    || stationProtocol.getTaskNo() <= 0
                    || !stationProtocol.isRunBlock()) {
                return;
            }
            List<Integer> runBlockReassignLocStationList = new ArrayList<>();
            for (StationObjModel stationObjModel : basDevp.getRunBlockReassignLocStationList$()) {
                runBlockReassignLocStationList.add(stationObjModel.getStationId());
            }
            List<Integer> outOrderStationIds = basDevp.getOutOrderIntList();
            WrkMast wrkMast = wrkMastService.selectByWorkNo(stationProtocol.getTaskNo());
            if (wrkMast == null) {
                News.info("输送站点号={} 运行阻塞,但无法找到对应任务,工作号={}", stationProtocol.getStationId(), stationProtocol.getTaskNo());
                return;
            }
            Object lock = redisUtil.get(RedisKeyType.CHECK_STATION_RUN_BLOCK_LIMIT_.key + stationProtocol.getTaskNo());
            if (lock != null) {
                return;
            }
            redisUtil.set(RedisKeyType.CHECK_STATION_RUN_BLOCK_LIMIT_.key + stationProtocol.getTaskNo(), "lock", 30);
            if (shouldUseRunBlockDirectReassign(wrkMast, stationProtocol.getStationId(), runBlockReassignLocStationList)) {
                if (stationMoveCoordinator != null) {
                    stationMoveCoordinator.withTaskDispatchLock(stationProtocol.getTaskNo(),
                            () -> {
                                executeRunBlockDirectReassign(basDevp, stationThread, stationProtocol, wrkMast);
                                return null;
                            });
                } else {
                    executeRunBlockDirectReassign(basDevp, stationThread, stationProtocol, wrkMast);
                }
                return;
            }
            Double pathLenFactor = stationOutboundDecisionSupport.resolveOutboundPathLenFactor(wrkMast);
            RerouteContext context = RerouteContext.create(
                    RerouteSceneType.RUN_BLOCK_REROUTE,
                    basDevp,
                    stationThread,
                    stationProtocol,
                    wrkMast,
                    outOrderStationIds,
                    pathLenFactor,
                    "checkStationRunBlock_reroute"
            ).withRunBlockCommand()
                    .withSuppressDispatchGuard()
                    .withCancelSessionBeforeDispatch()
                    .withResetSegmentCommandsBeforeDispatch();
            executeSharedReroute(context);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void checkStationOutOrder(BasDevp basDevp, StationObjModel stationObjModel) {
        try {
            if (basDevp == null || basDevp.getDevpNo() == null || stationObjModel == null || stationObjModel.getStationId() == null) {
                return;
            }
            StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo());
            if (stationThread == null) {
                return;
            }
            Map<Integer, StationProtocol> statusMap = stationThread.getStatusMap();
            List<StationObjModel> orderList = basDevp.getOutOrderList$();
            List<Integer> outOrderStationIds = basDevp.getOutOrderIntList();
            for (StationObjModel stationObjModel : orderList) {
                StationProtocol stationProtocol = statusMap.get(stationObjModel.getStationId());
                if (stationProtocol == null
                        || !stationProtocol.isAutoing()
                        || !stationProtocol.isLoading()
                        || stationProtocol.getTaskNo() <= 0
                        || stationProtocol.isRunBlock()
                        || !stationProtocol.getStationId().equals(stationProtocol.getTargetStaNo())) {
                    continue;
                }
                WrkMast wrkMast = wrkMastService.selectByWorkNo(stationProtocol.getTaskNo());
                if (wrkMast == null
                        || !Objects.equals(wrkMast.getWrkSts(), WrkStsType.STATION_RUN.sts)
                        || Objects.equals(stationProtocol.getStationId(), wrkMast.getStaNo())) {
                    continue;
                }
                if (stationOutboundDecisionSupport.shouldSkipOutOrderDispatchForExistingRoute(wrkMast.getWrkNo(), stationProtocol.getStationId())) {
                    continue;
                }
                Double pathLenFactor = stationOutboundDecisionSupport.resolveOutboundPathLenFactor(wrkMast);
                RerouteContext context = RerouteContext.create(
                        RerouteSceneType.OUT_ORDER,
                        basDevp,
                        stationThread,
                        stationProtocol,
                        wrkMast,
                        outOrderStationIds,
                        pathLenFactor,
                        "checkStationOutOrder"
                ).withDispatchDeviceNo(stationObjModel.getDeviceNo())
                        .withSuppressDispatchGuard()
                        .withOutOrderDispatchLock()
                        .withResetSegmentCommandsBeforeDispatch();
                executeSharedReroute(context);
            }
        }
    }
    public void watchCircleStation() {
        List<BasDevp> basDevps = basDevpService.list(new QueryWrapper<BasDevp>());
        for (BasDevp basDevp : basDevps) {
            StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo());
            if (stationThread == null) {
                continue;
            StationProtocol stationProtocol = statusMap == null ? null : statusMap.get(stationObjModel.getStationId());
            if (stationProtocol == null
                    || !stationProtocol.isAutoing()
                    || !stationProtocol.isLoading()
                    || stationProtocol.getTaskNo() <= 0
                    || stationProtocol.isRunBlock()
                    || !stationProtocol.getStationId().equals(stationProtocol.getTargetStaNo())) {
                return;
            }
            List<Integer> outOrderList = basDevp.getOutOrderIntList();
            for (StationProtocol stationProtocol : stationThread.getStatus()) {
                if (!stationProtocol.isAutoing()
                        || !stationProtocol.isLoading()
                        || stationProtocol.getTaskNo() <= 0
                        || !stationOutboundDecisionSupport.isWatchingCircleArrival(stationProtocol.getTaskNo(), stationProtocol.getStationId())) {
                    continue;
                }
                WrkMast wrkMast = wrkMastService.selectByWorkNo(stationProtocol.getTaskNo());
                if (wrkMast == null
                        || !Objects.equals(wrkMast.getWrkSts(), WrkStsType.STATION_RUN.sts)
                        || Objects.equals(stationProtocol.getStationId(), wrkMast.getStaNo())) {
                    continue;
                }
                Double pathLenFactor = stationOutboundDecisionSupport.resolveOutboundPathLenFactor(wrkMast);
                RerouteContext context = RerouteContext.create(
                        RerouteSceneType.WATCH_CIRCLE,
                        basDevp,
                        stationThread,
                        stationProtocol,
                        wrkMast,
                        outOrderList,
                        pathLenFactor,
                        "watchCircleStation"
                ).withSuppressDispatchGuard()
                        .withOutOrderDispatchLock()
                        .withResetSegmentCommandsBeforeDispatch();
                executeSharedReroute(context);
            WrkMast wrkMast = wrkMastService.selectByWorkNo(stationProtocol.getTaskNo());
            if (wrkMast == null
                    || !Objects.equals(wrkMast.getWrkSts(), WrkStsType.STATION_RUN.sts)
                    || Objects.equals(stationProtocol.getStationId(), wrkMast.getStaNo())) {
                return;
            }
            if (stationOutboundDecisionSupport.shouldSkipOutOrderDispatchForExistingRoute(wrkMast.getWrkNo(), stationProtocol.getStationId())) {
                return;
            }
            Double pathLenFactor = stationOutboundDecisionSupport.resolveOutboundPathLenFactor(wrkMast);
            RerouteContext context = RerouteContext.create(
                    RerouteSceneType.OUT_ORDER,
                    basDevp,
                    stationThread,
                    stationProtocol,
                    wrkMast,
                    basDevp.getOutOrderIntList(),
                    pathLenFactor,
                    "checkStationOutOrder"
            ).withDispatchDeviceNo(stationObjModel.getDeviceNo())
                    .withSuppressDispatchGuard()
                    .withOutOrderDispatchLock()
                    .withResetSegmentCommandsBeforeDispatch();
            executeSharedReroute(context);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
@@ -375,32 +322,24 @@
                && runBlockReassignLocStationList.contains(stationId);
    }
    public boolean shouldSkipIdleRecoverForRecentDispatch(Integer taskNo, Integer stationId) {
        if (taskNo == null || taskNo <= 0 || stationId == null) {
    private boolean shouldSkipRunBlockStation(BasDevp basDevp, Integer stationId) {
        if (basDevp == null || stationId == null) {
            return false;
        }
        long thresholdMs = STATION_IDLE_RECOVER_SECONDS * 1000L;
        StationMoveSession session = stationMoveCoordinator == null ? null : stationMoveCoordinator.loadSession(taskNo);
        if (session != null && session.isActive() && session.getLastIssuedAt() != null) {
            if (Objects.equals(stationId, session.getCurrentStationId())
                    || Objects.equals(stationId, session.getDispatchStationId())
                    || session.containsStation(stationId)) {
                long elapsedMs = System.currentTimeMillis() - session.getLastIssuedAt();
                if (elapsedMs < thresholdMs) {
                    stationDispatchRuntimeStateSupport.saveIdleTrack(new StationTaskIdleTrack(taskNo, stationId, System.currentTimeMillis()));
                    News.info("输送站点任务刚完成命令下发,已跳过停留重算。站点号={},工作号={},距上次下发={}ms,routeVersion={}",
                            stationId, taskNo, elapsedMs, session.getRouteVersion());
                    return true;
                }
        return containsStation(basDevp.getBarcodeStationList$(), stationId)
                || containsStation(basDevp.getInStationList$(), stationId);
    }
    private boolean containsStation(List<StationObjModel> stationList, Integer stationId) {
        if (stationList == null || stationList.isEmpty() || stationId == null) {
            return false;
        }
        for (StationObjModel stationObjModel : stationList) {
            if (stationObjModel != null && Objects.equals(stationObjModel.getStationId(), stationId)) {
                return true;
            }
        }
        if (!stationDispatchRuntimeStateSupport.hasRecentIssuedMoveCommand(taskNo, stationId, thresholdMs)) {
            return false;
        }
        stationDispatchRuntimeStateSupport.saveIdleTrack(new StationTaskIdleTrack(taskNo, stationId, System.currentTimeMillis()));
        News.info("输送站点任务刚完成命令下发,已跳过停留重算。站点号={},工作号={},距最近命令下发<{}ms,routeVersion={}",
                stationId, taskNo, thresholdMs, session == null ? null : session.getRouteVersion());
        return true;
        return false;
    }
    private RerouteExecutionResult executeReroutePlanWithTaskLock(RerouteContext context,
@@ -409,18 +348,8 @@
                                                                  Integer taskNo,
                                                                  Integer stationId) {
        boolean runBlockReroute = context.sceneType() == RerouteSceneType.RUN_BLOCK_REROUTE;
        if (context.checkRecentDispatch()
                && shouldSkipIdleRecoverForRecentDispatch(taskNo, stationId)) {
            return RerouteExecutionResult.skip("recent-dispatch");
        }
        int currentTaskBufferCommandCount = countCurrentTaskBufferCommands(stationProtocol.getTaskBufferItems(), taskNo);
        if (currentTaskBufferCommandCount > 0 && !runBlockReroute) {
            if (context.sceneType() == RerouteSceneType.IDLE_RECOVER) {
                News.info("输送站点任务停留超时,但缓存区仍存在当前任务命令,已跳过重算。站点号={},工作号={},当前任务命令数={}",
                        stationId,
                        taskNo,
                        currentTaskBufferCommandCount);
            }
            return RerouteExecutionResult.skip("buffer-has-current-task");
        }
        if (currentTaskBufferCommandCount > 0 && runBlockReroute) {
@@ -440,39 +369,23 @@
            return RerouteExecutionResult.skip("out-order-lock");
        }
        if (context.cancelSessionBeforeDispatch() && stationMoveCoordinator != null) {
            stationMoveCoordinator.markCancelPending(taskNo, "reroute_pending");
        }
        if (runBlockReroute) {
            if (context.cancelSessionBeforeDispatch() && stationMoveCoordinator != null) {
                stationMoveCoordinator.cancelSession(taskNo);
            }
            if (context.resetSegmentCommandsBeforeDispatch()) {
                stationDispatchRuntimeStateSupport.signalSegmentReset(taskNo, STATION_MOVE_RESET_WAIT_MS);
            }
        }
        if (!runBlockReroute
                && context.cancelSessionBeforeDispatch() && stationMoveCoordinator != null) {
            stationMoveCoordinator.cancelSession(taskNo);
        }
        if (!isBlank(context.executionLockKey())
                && !stationDispatchRuntimeStateSupport.tryAcquireLock(context.executionLockKey(), context.executionLockSeconds())) {
                return RerouteExecutionResult.skip("scene-lock");
        }
        if (!runBlockReroute && context.resetSegmentCommandsBeforeDispatch()) {
        if (context.resetSegmentCommandsBeforeDispatch()) {
            stationDispatchRuntimeStateSupport.signalSegmentReset(taskNo, STATION_MOVE_RESET_WAIT_MS);
        }
        int clearedCommandCount = 0;
        if (context.clearIdleIssuedCommands()) {
            clearedCommandCount = stationDispatchRuntimeStateSupport.clearIssuedMoveCommandsDuringIdleStay(context.idleTrack(), taskNo, stationId);
        }
        boolean offered = offerDevpCommandWithDedup(context.dispatchDeviceNo(), plan.command(), plan.dispatchScene());
        if (!offered) {
            return RerouteExecutionResult.skip("dispatch-dedup");
        }
        if (context.cancelSessionBeforeDispatch() && stationMoveCoordinator != null) {
            stationMoveCoordinator.markCancelPending(taskNo, "reroute_pending");
            stationMoveCoordinator.cancelSession(taskNo);
        }
        applyRerouteDispatchEffects(context, plan, clearedCommandCount);
@@ -515,17 +428,6 @@
                    dispatchDecision != null && dispatchDecision.isCircle()
            );
        }
        if (context.sceneType() == RerouteSceneType.IDLE_RECOVER) {
            stationDispatchRuntimeStateSupport.saveIdleTrack(new StationTaskIdleTrack(wrkMast.getWrkNo(), stationProtocol.getStationId(), System.currentTimeMillis()));
            News.info("输送站点任务停留{}秒未运行,已重新计算路径并重启运行,站点号={},目标站={},工作号={},清理旧分段命令数={},命令数据={}",
                    STATION_IDLE_RECOVER_SECONDS,
                    stationProtocol.getStationId(),
                    plan.command().getTargetStaNo(),
                    wrkMast.getWrkNo(),
                    clearedCommandCount,
                    JSON.toJSONString(plan.command()));
            return;
        }
        if (context.sceneType() == RerouteSceneType.RUN_BLOCK_REROUTE) {
            News.info("输送站点堵塞后重新计算路径命令下发成功,站点号={},工作号={},命令数据={}",
                    stationProtocol.getStationId(),
@@ -536,51 +438,6 @@
        if (context.sceneType() == RerouteSceneType.OUT_ORDER) {
            News.info(dispatchDecision != null && dispatchDecision.isCircle() ? "{}任务进行绕圈" : "{}任务直接去目标点", wrkMast.getWrkNo());
        }
    }
    private void checkStationIdleRecover(BasDevp basDevp,
                                         StationThread stationThread,
                                         StationProtocol stationProtocol,
                                         List<Integer> outOrderList) {
        if (stationProtocol == null || stationProtocol.getTaskNo() == null || stationProtocol.getTaskNo() <= 0) {
            return;
        }
        if (!Objects.equals(stationProtocol.getStationId(), stationProtocol.getTargetStaNo())) {
            return;
        }
        StationTaskIdleTrack idleTrack = stationDispatchRuntimeStateSupport.touchIdleTrack(stationProtocol.getTaskNo(), stationProtocol.getStationId());
        if (shouldSkipIdleRecoverForRecentDispatch(stationProtocol.getTaskNo(), stationProtocol.getStationId())) {
            return;
        }
        if (idleTrack == null || !idleTrack.isTimeout(STATION_IDLE_RECOVER_SECONDS)) {
            return;
        }
        WrkMast wrkMast = wrkMastService.selectByWorkNo(stationProtocol.getTaskNo());
        if (!canRecoverIdleStationTask(wrkMast, stationProtocol.getStationId())) {
            return;
        }
        Object lock = redisUtil.get(RedisKeyType.CHECK_STATION_IDLE_RECOVER_LIMIT_.key + stationProtocol.getTaskNo());
        if (lock != null) {
            return;
        }
        Double pathLenFactor = stationOutboundDecisionSupport.resolveOutboundPathLenFactor(wrkMast);
        RerouteContext context = RerouteContext.create(
                RerouteSceneType.IDLE_RECOVER,
                basDevp,
                stationThread,
                stationProtocol,
                wrkMast,
                outOrderList,
                pathLenFactor,
                "checkStationIdleRecover"
        ).withCancelSessionBeforeDispatch()
                .withExecutionLock(RedisKeyType.CHECK_STATION_IDLE_RECOVER_LIMIT_.key + stationProtocol.getTaskNo(), STATION_IDLE_RECOVER_LIMIT_SECONDS)
                .withResetSegmentCommandsBeforeDispatch()
                .clearIdleIssuedCommands(idleTrack);
        executeSharedReroute(context);
    }
    private void executeRunBlockDirectReassign(BasDevp basDevp,
@@ -600,9 +457,6 @@
                    stationProtocol.getTaskNo(),
                    currentTaskBufferCommandCount);
            return;
        }
        if (stationMoveCoordinator != null) {
            stationMoveCoordinator.cancelSession(wrkMast.getWrkNo());
        }
        String response = wmsOperateUtils.applyReassignTaskLocNo(wrkMast.getWrkNo(), stationProtocol.getStationId());
        if (Cools.isEmpty(response)) {
@@ -685,6 +539,8 @@
            return;
        }
        if (stationMoveCoordinator != null) {
            stationMoveCoordinator.markCancelPending(wrkMast.getWrkNo(), "reroute_pending");
            stationMoveCoordinator.cancelSession(wrkMast.getWrkNo());
            stationMoveCoordinator.recordDispatch(
                    wrkMast.getWrkNo(),
                    stationProtocol.getStationId(),
@@ -693,17 +549,6 @@
                    false
            );
        }
    }
    private boolean canRecoverIdleStationTask(WrkMast wrkMast, Integer currentStationId) {
        if (wrkMast == null || currentStationId == null || wrkMast.getStaNo() == null) {
            return false;
        }
        if (Objects.equals(currentStationId, wrkMast.getStaNo())) {
            return false;
        }
        return Objects.equals(wrkMast.getWrkSts(), WrkStsType.INBOUND_STATION_RUN.sts)
                || Objects.equals(wrkMast.getWrkSts(), WrkStsType.STATION_RUN.sts);
    }
    private int countCurrentTaskBufferCommands(List<StationTaskBufferItem> taskBufferItems, Integer currentTaskNo) {