| | |
| | | |
| | | 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 = 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) { |
| | |
| | | stationProtocol.getTaskNo() |
| | | ); |
| | | if (currentTaskBufferCommandCount > 0) { |
| | | News.info("输送站点运行堵塞重分配已跳过,缓存区仍存在当前任务命令。站点号={},工作号={},当前任务命令数={}", |
| | | News.info("输送站点运行堵塞重分配检测到旧分段命令残留,将先重置本地分段状态后继续重发。站点号={},工作号={},当前任务命令数={}", |
| | | stationProtocol.getStationId(), |
| | | stationProtocol.getTaskNo(), |
| | | currentTaskBufferCommandCount); |
| | | } |
| | | if (stationDispatchRuntimeStateSupport.hasRunBlockDirectReassignLimit( |
| | | wrkMast.getWrkNo(), |
| | | stationProtocol.getStationId())) { |
| | | News.info("输送站点运行堵塞重分配已跳过,8分钟内不允许重复申请。站点号={},工作号={}", |
| | | stationProtocol.getStationId(), |
| | | wrkMast.getWrkNo()); |
| | | return; |
| | | } |
| | | String response = wmsOperateUtils.applyReassignTaskLocNo(wrkMast.getWrkNo(), stationProtocol.getStationId()); |
| | |
| | | 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; |