Junjie
2026-04-13 75cc46160a689ee0de4318787f0be827ea19ff4d
src/main/java/com/zy/core/utils/station/StationRerouteProcessor.java
@@ -50,9 +50,8 @@
@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;
    private static final int RUN_BLOCK_DIRECT_REASSIGN_LIMIT_SECONDS = 15 * 60;
    @Autowired
    private BasDevpService basDevpService;
@@ -75,29 +74,12 @@
    @Autowired
    private StationDispatchRuntimeStateSupport stationDispatchRuntimeStateSupport;
    public void checkStationRunBlock() {
        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 == null || stationProtocol.getStationId() == null) {
                        continue;
                    }
                    checkStationRunBlock(basDevp, stationProtocol.getStationId());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void checkStationRunBlock(BasDevp basDevp, Integer stationId) {
        try {
            if (basDevp == null || basDevp.getDevpNo() == null || stationId == null) {
                return;
            }
            if (shouldSkipRunBlockStation(basDevp, stationId)) {
                return;
            }
            StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo());
@@ -131,10 +113,18 @@
            if (lock != null) {
                return;
            }
            redisUtil.set(RedisKeyType.CHECK_STATION_RUN_BLOCK_LIMIT_.key + stationProtocol.getTaskNo(), "lock", 15);
            redisUtil.set(RedisKeyType.CHECK_STATION_RUN_BLOCK_LIMIT_.key + stationProtocol.getTaskNo(), "lock", 30);
            if (shouldUseRunBlockDirectReassign(wrkMast, stationProtocol.getStationId(), runBlockReassignLocStationList)) {
                executeRunBlockDirectReassign(basDevp, stationThread, stationProtocol, wrkMast);
                if (stationMoveCoordinator != null) {
                    stationMoveCoordinator.withTaskDispatchLock(stationProtocol.getTaskNo(),
                            () -> {
                                executeRunBlockDirectReassign(basDevp, stationThread, stationProtocol, wrkMast);
                                return null;
                            });
                } else {
                    executeRunBlockDirectReassign(basDevp, stationThread, stationProtocol, wrkMast);
                }
                return;
            }
@@ -155,63 +145,6 @@
            executeSharedReroute(context);
        } 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 != null && stationProtocol.getStationId() != null) {
                        checkStationIdleRecover(basDevp, stationProtocol.getStationId());
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void checkStationIdleRecover(BasDevp basDevp, Integer stationId) {
        try {
            if (basDevp == null || basDevp.getDevpNo() == null || stationId == null) {
                return;
            }
            if (!isIdleRecoverCandidateStation(basDevp, stationId)) {
                return;
            }
            StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo());
            if (stationThread == null) {
                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;
            }
            checkStationIdleRecover(basDevp, stationThread, stationProtocol, basDevp.getOutOrderIntList());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void checkStationOutOrder() {
        List<BasDevp> basDevps = basDevpService.list(new QueryWrapper<BasDevp>());
        for (BasDevp basDevp : basDevps) {
            List<StationObjModel> orderList = basDevp.getOutOrderList$();
            for (StationObjModel stationObjModel : orderList) {
                checkStationOutOrder(basDevp, stationObjModel);
            }
        }
    }
@@ -257,67 +190,6 @@
                    "checkStationOutOrder"
            ).withDispatchDeviceNo(stationObjModel.getDeviceNo())
                    .withSuppressDispatchGuard()
                    .withOutOrderDispatchLock()
                    .withResetSegmentCommandsBeforeDispatch();
            executeSharedReroute(context);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    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;
            }
            for (StationProtocol stationProtocol : stationThread.getStatus()) {
                if (stationProtocol == null || stationProtocol.getStationId() == null) {
                    continue;
                }
                watchCircleStation(basDevp, stationProtocol.getStationId());
            }
        }
    }
    public void watchCircleStation(BasDevp basDevp, Integer stationId) {
        try {
            if (basDevp == null || basDevp.getDevpNo() == null || stationId == null) {
                return;
            }
            StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo());
            if (stationThread == null) {
                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
                    || !stationOutboundDecisionSupport.isWatchingCircleArrival(stationProtocol.getTaskNo(), stationProtocol.getStationId())) {
                return;
            }
            WrkMast wrkMast = wrkMastService.selectByWorkNo(stationProtocol.getTaskNo());
            if (wrkMast == null
                    || !Objects.equals(wrkMast.getWrkSts(), WrkStsType.STATION_RUN.sts)
                    || Objects.equals(stationProtocol.getStationId(), wrkMast.getStaNo())) {
                return;
            }
            Double pathLenFactor = stationOutboundDecisionSupport.resolveOutboundPathLenFactor(wrkMast);
            RerouteContext context = RerouteContext.create(
                    RerouteSceneType.WATCH_CIRCLE,
                    basDevp,
                    stationThread,
                    stationProtocol,
                    wrkMast,
                    basDevp.getOutOrderIntList(),
                    pathLenFactor,
                    "watchCircleStation"
            ).withSuppressDispatchGuard()
                    .withOutOrderDispatchLock()
                    .withResetSegmentCommandsBeforeDispatch();
            executeSharedReroute(context);
@@ -451,41 +323,12 @@
                && runBlockReassignLocStationList.contains(stationId);
    }
    public boolean shouldSkipIdleRecoverForRecentDispatch(Integer taskNo, Integer stationId) {
        if (taskNo == null || taskNo <= 0 || 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;
                }
            }
        }
        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;
    }
    private boolean isIdleRecoverCandidateStation(BasDevp basDevp, Integer stationId) {
    private boolean shouldSkipRunBlockStation(BasDevp basDevp, Integer stationId) {
        if (basDevp == null || stationId == null) {
            return false;
        }
        return !containsStation(basDevp.getBarcodeStationList$(), stationId)
                && !containsStation(basDevp.getInStationList$(), stationId)
                && !containsStation(basDevp.getOutStationList$(), stationId);
        return containsStation(basDevp.getBarcodeStationList$(), stationId)
                || containsStation(basDevp.getInStationList$(), stationId);
    }
    private boolean containsStation(List<StationObjModel> stationList, Integer stationId) {
@@ -506,18 +349,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) {
@@ -537,39 +370,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);
@@ -612,17 +429,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(),
@@ -633,51 +439,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,
@@ -692,14 +453,18 @@
                stationProtocol.getTaskNo()
        );
        if (currentTaskBufferCommandCount > 0) {
            News.info("输送站点运行堵塞重分配已跳过,缓存区仍存在当前任务命令。站点号={},工作号={},当前任务命令数={}",
            News.info("输送站点运行堵塞重分配检测到旧分段命令残留,将先重置本地分段状态后继续重发。站点号={},工作号={},当前任务命令数={}",
                    stationProtocol.getStationId(),
                    stationProtocol.getTaskNo(),
                    currentTaskBufferCommandCount);
            return;
        }
        if (stationMoveCoordinator != null) {
            stationMoveCoordinator.cancelSession(wrkMast.getWrkNo());
        if (stationDispatchRuntimeStateSupport.hasRunBlockDirectReassignLimit(
                wrkMast.getWrkNo(),
                stationProtocol.getStationId())) {
            News.info("输送站点运行堵塞重分配已跳过,15分钟内不允许重复申请。站点号={},工作号={}",
                    stationProtocol.getStationId(),
                    wrkMast.getWrkNo());
            return;
        }
        String response = wmsOperateUtils.applyReassignTaskLocNo(wrkMast.getWrkNo(), stationProtocol.getStationId());
        if (Cools.isEmpty(response)) {
@@ -777,11 +542,18 @@
        if (!wrkMastService.updateById(wrkMast)) {
            return;
        }
        stationDispatchRuntimeStateSupport.recordRunBlockDirectReassignLimit(
                wrkMast.getWrkNo(),
                stationProtocol.getStationId(),
                RUN_BLOCK_DIRECT_REASSIGN_LIMIT_SECONDS);
        stationDispatchRuntimeStateSupport.signalSegmentReset(wrkMast.getWrkNo(), STATION_MOVE_RESET_WAIT_MS);
        boolean offered = offerDevpCommandWithDedup(basDevp.getDevpNo(), command, "checkStationRunBlock_direct");
        if (!offered) {
            return;
        }
        if (stationMoveCoordinator != null) {
            stationMoveCoordinator.markCancelPending(wrkMast.getWrkNo(), "reroute_pending");
            stationMoveCoordinator.cancelSession(wrkMast.getWrkNo());
            stationMoveCoordinator.recordDispatch(
                    wrkMast.getWrkNo(),
                    stationProtocol.getStationId(),
@@ -790,17 +562,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) {