| | |
| | | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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 |
| | |
| | | private StationOutboundDecisionSupport stationOutboundDecisionSupport; |
| | | @Autowired |
| | | private StationDispatchRuntimeStateSupport stationDispatchRuntimeStateSupport; |
| | | @Autowired |
| | | private NavigateUtils navigateUtils; |
| | | |
| | | public void checkStationRunBlock(BasDevp basDevp, Integer stationId) { |
| | | try { |
| | |
| | | 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) { |
| | |
| | | if (basDevp == null || stationThread == null || stationProtocol == null || wrkMast == null) { |
| | | return; |
| | | } |
| | | if (isDirectReassignContextStale(stationProtocol, wrkMast)) { |
| | | return; |
| | | } |
| | | int currentTaskBufferCommandCount = countCurrentTaskBufferCommands( |
| | | stationProtocol.getTaskBufferItems(), |
| | | stationProtocol.getTaskNo() |
| | |
| | | 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; |
| | |
| | | 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) { |
| | |
| | | false |
| | | ); |
| | | } |
| | | } |
| | | |
| | | private boolean isDirectReassignContextStale(StationProtocol stationProtocol, WrkMast wrkMast) { |
| | | if (stationProtocol == null || wrkMast == null || stationMoveCoordinator == null) { |
| | | return false; |
| | | } |
| | | Integer taskNo = wrkMast.getWrkNo(); |
| | | Integer triggerStationId = stationProtocol.getStationId(); |
| | | if (taskNo == null || taskNo <= 0 || triggerStationId == null) { |
| | | return false; |
| | | } |
| | | StationMoveSession session = stationMoveCoordinator.loadSession(taskNo); |
| | | if (session == null || !session.isActive()) { |
| | | return false; |
| | | } |
| | | Integer currentStationId = session.getCurrentStationId(); |
| | | if (currentStationId == null || Objects.equals(currentStationId, triggerStationId)) { |
| | | return false; |
| | | } |
| | | News.info("输送站点运行堵塞重分配已跳过,任务已离开触发站点。触发站点={},当前站点={},工作号={}", |
| | | triggerStationId, |
| | | currentStationId, |
| | | taskNo); |
| | | return true; |
| | | } |
| | | |
| | | private int countCurrentTaskBufferCommands(List<StationTaskBufferItem> taskBufferItems, Integer currentTaskNo) { |