From f7d2eda120867b3c5a2d9001d5f5c9d0396c65bd Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期二, 14 四月 2026 12:41:13 +0800
Subject: [PATCH] #命令下发队列优化

---
 src/main/java/com/zy/core/utils/station/StationRerouteProcessor.java |  210 ++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 178 insertions(+), 32 deletions(-)

diff --git a/src/main/java/com/zy/core/utils/station/StationRerouteProcessor.java b/src/main/java/com/zy/core/utils/station/StationRerouteProcessor.java
index f854f5f..a433445 100644
--- a/src/main/java/com/zy/core/utils/station/StationRerouteProcessor.java
+++ b/src/main/java/com/zy/core/utils/station/StationRerouteProcessor.java
@@ -2,18 +2,18 @@
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.core.common.Cools;
 import com.core.exception.CoolException;
 import com.zy.asrs.entity.BasDevp;
 import com.zy.asrs.entity.LocMast;
 import com.zy.asrs.entity.WrkMast;
-import com.zy.asrs.service.BasDevpService;
 import com.zy.asrs.service.LocMastService;
 import com.zy.asrs.service.WrkMastService;
 import com.zy.common.entity.FindCrnNoResult;
+import com.zy.common.model.NavigateNode;
 import com.zy.common.model.StartupDto;
 import com.zy.common.service.CommonService;
+import com.zy.common.utils.NavigateUtils;
 import com.zy.common.utils.RedisUtil;
 import com.zy.core.News;
 import com.zy.core.cache.SlaveConnection;
@@ -29,7 +29,6 @@
 import com.zy.core.model.protocol.StationProtocol;
 import com.zy.core.model.protocol.StationTaskBufferItem;
 import com.zy.core.move.StationMoveCoordinator;
-import com.zy.core.move.StationMoveSession;
 import com.zy.core.thread.StationThread;
 import com.zy.core.utils.station.model.OutOrderDispatchDecision;
 import com.zy.core.utils.station.model.RerouteCommandPlan;
@@ -42,6 +41,7 @@
 import org.springframework.stereotype.Component;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
@@ -51,10 +51,9 @@
 public class StationRerouteProcessor {
     private static final int OUT_ORDER_DISPATCH_LIMIT_SECONDS = 2;
     private static final long STATION_MOVE_RESET_WAIT_MS = 1000L;
-    private static final int RUN_BLOCK_DIRECT_REASSIGN_LIMIT_SECONDS = 15 * 60;
+    private static final int RUN_BLOCK_DIRECT_REASSIGN_LIMIT_SECONDS = 8 * 60;
+    private static final int RUN_BLOCK_DIRECT_REASSIGN_NEAREST_CACHE_SECONDS = 60 * 60 * 24;
 
-    @Autowired
-    private BasDevpService basDevpService;
     @Autowired
     private WrkMastService wrkMastService;
     @Autowired
@@ -73,6 +72,8 @@
     private StationOutboundDecisionSupport stationOutboundDecisionSupport;
     @Autowired
     private StationDispatchRuntimeStateSupport stationDispatchRuntimeStateSupport;
+    @Autowired
+    private NavigateUtils navigateUtils;
 
     public void checkStationRunBlock(BasDevp basDevp, Integer stationId) {
         try {
@@ -316,11 +317,141 @@
     public boolean shouldUseRunBlockDirectReassign(WrkMast wrkMast,
                                                    Integer stationId,
                                                    List<Integer> runBlockReassignLocStationList) {
-        return wrkMast != null
-                && Objects.equals(wrkMast.getIoType(), WrkIoType.IN.id)
-                && stationId != null
-                && runBlockReassignLocStationList != null
-                && runBlockReassignLocStationList.contains(stationId);
+        if (wrkMast == null || stationId == null) {
+            return false;
+        }
+        if (!Objects.equals(wrkMast.getIoType(), WrkIoType.IN.id)) {
+            return false;
+        }
+        if (runBlockReassignLocStationList == null || !runBlockReassignLocStationList.contains(stationId)) {
+            return false;
+        }
+        if (shouldForceRunBlockPathReroute(wrkMast, stationId, runBlockReassignLocStationList)) {
+            return false;
+        }
+        return true;
+    }
+
+    private boolean shouldForceRunBlockPathReroute(WrkMast wrkMast,
+                                                   Integer stationId,
+                                                   List<Integer> runBlockReassignLocStationList) {
+        if (wrkMast == null || stationId == null) {
+            return false;
+        }
+        Integer nearestStationId = resolveNearestRunBlockDirectReassignStationId(wrkMast, runBlockReassignLocStationList);
+        return nearestStationId != null && !Objects.equals(stationId, nearestStationId);
+    }
+
+    private Integer resolveNearestRunBlockDirectReassignStationId(WrkMast wrkMast,
+                                                                  List<Integer> runBlockReassignLocStationList) {
+        if (wrkMast == null
+                || wrkMast.getStaNo() == null
+                || navigateUtils == null
+                || runBlockReassignLocStationList == null
+                || runBlockReassignLocStationList.isEmpty()) {
+            return null;
+        }
+        Integer targetStationId = wrkMast.getStaNo();
+        Integer cachedStationId = loadCachedNearestRunBlockDirectReassignStationId(targetStationId, runBlockReassignLocStationList);
+        if (cachedStationId != null) {
+            return cachedStationId;
+        }
+        Integer nearestStationId = null;
+        int nearestPathLen = Integer.MAX_VALUE;
+        for (Integer candidateStationId : runBlockReassignLocStationList) {
+            if (candidateStationId == null) {
+                continue;
+            }
+            List<NavigateNode> path = navigateUtils.calcOptimalPathByStationId(candidateStationId, targetStationId, wrkMast.getWrkNo(), null);
+            if (path == null || path.isEmpty()) {
+                continue;
+            }
+            int pathLen = countStationNodes(path);
+            if (pathLen <= 0) {
+                continue;
+            }
+            if (pathLen < nearestPathLen
+                    || (pathLen == nearestPathLen && nearestStationId != null && candidateStationId < nearestStationId)) {
+                nearestStationId = candidateStationId;
+                nearestPathLen = pathLen;
+            }
+        }
+        cacheNearestRunBlockDirectReassignStationId(targetStationId, runBlockReassignLocStationList, nearestStationId);
+        return nearestStationId;
+    }
+
+    private Integer loadCachedNearestRunBlockDirectReassignStationId(Integer targetStationId,
+                                                                     List<Integer> runBlockReassignLocStationList) {
+        String cacheKey = buildNearestRunBlockDirectReassignCacheKey(targetStationId, runBlockReassignLocStationList);
+        if (cacheKey == null || redisUtil == null) {
+            return null;
+        }
+        Object cacheValue = redisUtil.get(cacheKey);
+        if (cacheValue == null) {
+            return null;
+        }
+        try {
+            Integer stationId = Integer.valueOf(String.valueOf(cacheValue));
+            return runBlockReassignLocStationList.contains(stationId) ? stationId : null;
+        } catch (Exception ignore) {
+            return null;
+        }
+    }
+
+    private void cacheNearestRunBlockDirectReassignStationId(Integer targetStationId,
+                                                             List<Integer> runBlockReassignLocStationList,
+                                                             Integer nearestStationId) {
+        String cacheKey = buildNearestRunBlockDirectReassignCacheKey(targetStationId, runBlockReassignLocStationList);
+        if (cacheKey == null || nearestStationId == null || redisUtil == null) {
+            return;
+        }
+        redisUtil.set(cacheKey, nearestStationId, RUN_BLOCK_DIRECT_REASSIGN_NEAREST_CACHE_SECONDS);
+    }
+
+    private String buildNearestRunBlockDirectReassignCacheKey(Integer targetStationId,
+                                                              List<Integer> runBlockReassignLocStationList) {
+        if (targetStationId == null || runBlockReassignLocStationList == null || runBlockReassignLocStationList.isEmpty()) {
+            return null;
+        }
+        List<Integer> normalizedStationIdList = new ArrayList<>();
+        for (Integer stationId : runBlockReassignLocStationList) {
+            if (stationId != null && !normalizedStationIdList.contains(stationId)) {
+                normalizedStationIdList.add(stationId);
+            }
+        }
+        if (normalizedStationIdList.isEmpty()) {
+            return null;
+        }
+        Collections.sort(normalizedStationIdList);
+        return RedisKeyType.STATION_RUN_BLOCK_DIRECT_REASSIGN_NEAREST_CACHE_.key
+                + targetStationId
+                + "_"
+                + JSON.toJSONString(normalizedStationIdList);
+    }
+
+    private int countStationNodes(List<NavigateNode> path) {
+        if (path == null || path.isEmpty()) {
+            return 0;
+        }
+        int count = 0;
+        for (NavigateNode node : path) {
+            if (extractStationId(node) != null) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    private Integer extractStationId(NavigateNode node) {
+        if (node == null || Cools.isEmpty(node.getNodeValue())) {
+            return null;
+        }
+        try {
+            JSONObject valueObject = JSONObject.parseObject(node.getNodeValue());
+            return valueObject == null ? null : valueObject.getInteger("stationId");
+        } catch (Exception ignore) {
+            return null;
+        }
     }
 
     private boolean shouldSkipRunBlockStation(BasDevp basDevp, Integer stationId) {
@@ -380,13 +511,16 @@
 
         int clearedCommandCount = 0;
 
-        boolean offered = offerDevpCommandWithDedup(context.dispatchDeviceNo(), plan.command(), plan.dispatchScene());
-        if (!offered) {
-            return RerouteExecutionResult.skip("dispatch-dedup");
-        }
+        // 鍏堝彇娑堟棫 session 骞惰褰曟柊 session锛屽啀鍏ラ槦鍛戒护锛岄伩鍏嶆秷璐圭嚎绋嬪湪 session 鍐欏叆 Redis 鍓嶅彇鍒板懡浠ゅ鑷磋矾鐢辨牎楠屽け璐ャ��
         if (context.cancelSessionBeforeDispatch() && stationMoveCoordinator != null) {
             stationMoveCoordinator.markCancelPending(taskNo, "reroute_pending");
             stationMoveCoordinator.cancelSession(taskNo);
+        }
+        preRegisterDispatchSession(context, plan);
+
+        boolean offered = offerDevpCommandWithDedup(context.dispatchDeviceNo(), plan.command(), plan.dispatchScene());
+        if (!offered) {
+            return RerouteExecutionResult.skip("dispatch-dedup");
         }
 
         applyRerouteDispatchEffects(context, plan, clearedCommandCount);
@@ -400,6 +534,24 @@
         }
         RerouteCommandPlan plan = buildRerouteCommandPlan(context, decision);
         return executeReroutePlan(context, plan);
+    }
+
+    private void preRegisterDispatchSession(RerouteContext context, RerouteCommandPlan plan) {
+        if (context == null || plan == null || plan.command() == null || context.wrkMast() == null || context.stationProtocol() == null) {
+            return;
+        }
+        if (stationMoveCoordinator == null) {
+            return;
+        }
+        OutOrderDispatchDecision dispatchDecision =
+                plan.decision() == null ? null : plan.decision().dispatchDecision();
+        stationMoveCoordinator.recordDispatch(
+                context.wrkMast().getWrkNo(),
+                context.stationProtocol().getStationId(),
+                plan.dispatchScene(),
+                plan.command(),
+                dispatchDecision != null && dispatchDecision.isCircle()
+        );
     }
 
     private void applyRerouteDispatchEffects(RerouteContext context,
@@ -420,15 +572,6 @@
                 dispatchDecision,
                 plan.command()
         );
-        if (stationMoveCoordinator != null) {
-            stationMoveCoordinator.recordDispatch(
-                    wrkMast.getWrkNo(),
-                    stationProtocol.getStationId(),
-                    plan.dispatchScene(),
-                    plan.command(),
-                    dispatchDecision != null && dispatchDecision.isCircle()
-            );
-        }
         if (context.sceneType() == RerouteSceneType.RUN_BLOCK_REROUTE) {
             News.info("杈撻�佺珯鐐瑰牭濉炲悗閲嶆柊璁$畻璺緞鍛戒护涓嬪彂鎴愬姛锛岀珯鐐瑰彿={}锛屽伐浣滃彿={}锛屽懡浠ゆ暟鎹�={}",
                     stationProtocol.getStationId(),
@@ -458,11 +601,10 @@
                     stationProtocol.getTaskNo(),
                     currentTaskBufferCommandCount);
         }
-        if (!stationDispatchRuntimeStateSupport.tryAcquireRunBlockDirectReassignLock(
+        if (stationDispatchRuntimeStateSupport.hasRunBlockDirectReassignLimit(
                 wrkMast.getWrkNo(),
-                stationProtocol.getStationId(),
-                RUN_BLOCK_DIRECT_REASSIGN_LIMIT_SECONDS)) {
-            News.info("杈撻�佺珯鐐硅繍琛屽牭濉為噸鍒嗛厤宸茶烦杩囷紝15鍒嗛挓鍐呬笉鍏佽閲嶅鐢宠銆傜珯鐐瑰彿={}锛屽伐浣滃彿={}",
+                stationProtocol.getStationId())) {
+            News.info("杈撻�佺珯鐐硅繍琛屽牭濉為噸鍒嗛厤宸茶烦杩囷紝8鍒嗛挓鍐呬笉鍏佽閲嶅鐢宠銆傜珯鐐瑰彿={}锛屽伐浣滃彿={}",
                     stationProtocol.getStationId(),
                     wrkMast.getWrkNo());
             return;
@@ -543,11 +685,11 @@
         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());
@@ -559,6 +701,10 @@
                     false
             );
         }
+        boolean offered = offerDevpCommandWithDedup(basDevp.getDevpNo(), command, "checkStationRunBlock_direct");
+        if (!offered) {
+            News.warn("杈撻�佺珯鐐瑰牭濉炵洿娲惧懡浠ゅ叆闃熻鎷掔粷(鍙兘閲嶅)锛岀珯鐐瑰彿={}锛屽伐浣滃彿={}", stationProtocol.getStationId(), wrkMast.getWrkNo());
+        }
     }
 
     private int countCurrentTaskBufferCommands(List<StationTaskBufferItem> taskBufferItems, Integer currentTaskNo) {

--
Gitblit v1.9.1