| | |
| | | @Component |
| | | public class StationOperateProcessUtils { |
| | | private static final int LOOP_LOAD_RESERVE_EXPIRE_SECONDS = 120; |
| | | private static final int OUT_ORDER_DISPATCH_LIMIT_SECONDS = 10; |
| | | 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 = 10; |
| | | private static final int STATION_IDLE_TRACK_EXPIRE_SECONDS = 60 * 60; |
| | | private static final long STATION_MOVE_RESET_WAIT_MS = 1000L; |
| | | private static final String IDLE_RECOVER_CLEARED_MEMO = "idleRecoverRerouteCleared"; |
| | | |
| | | @Autowired |
| | | private BasDevpService basDevpService; |
| | |
| | | for (WrkMast wrkMast : wrkMasts) { |
| | | Integer wrkNo = wrkMast.getWrkNo(); |
| | | Integer targetStaNo = wrkMast.getStaNo(); |
| | | if (wrkNo == null || targetStaNo == null) { |
| | | continue; |
| | | } |
| | | |
| | | boolean complete = false; |
| | | Integer targetDeviceNo = null; |
| | | BasStation basStation = basStationService.getOne(new QueryWrapper<BasStation>().eq("station_id", targetStaNo)); |
| | | if (basStation == null) { |
| | | continue; |
| | | } |
| | | |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basStation.getDeviceNo()); |
| | | if (stationThread == null) { |
| | | continue; |
| | | } |
| | | |
| | | Map<Integer, StationProtocol> statusMap = stationThread.getStatusMap(); |
| | | StationProtocol stationProtocol = statusMap.get(basStation.getStationId()); |
| | | if (stationProtocol == null) { |
| | | continue; |
| | | } |
| | | |
| | | if (stationProtocol.getTaskNo().equals(wrkNo)) { |
| | | complete = true; |
| | | if (basStation != null) { |
| | | targetDeviceNo = basStation.getDeviceNo(); |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basStation.getDeviceNo()); |
| | | if (stationThread != null) { |
| | | Map<Integer, StationProtocol> statusMap = stationThread.getStatusMap(); |
| | | StationProtocol stationProtocol = statusMap.get(basStation.getStationId()); |
| | | if (stationProtocol != null && wrkNo.equals(stationProtocol.getTaskNo())) { |
| | | complete = true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (complete) { |
| | | wrkMast.setWrkSts(WrkStsType.STATION_RUN_COMPLETE.sts); |
| | | wrkMast.setIoTime(new Date()); |
| | | wrkMastService.updateById(wrkMast); |
| | | notifyUtils.notify(String.valueOf(SlaveType.Devp), basStation.getDeviceNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.STATION_OUT_TASK_RUN_COMPLETE, null); |
| | | redisUtil.set(RedisKeyType.STATION_OUT_EXECUTE_COMPLETE_LIMIT.key + wrkMast.getWrkNo(), "lock", 60); |
| | | completeStationRunTask(wrkMast, targetDeviceNo); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | private void completeStationRunTask(WrkMast wrkMast, Integer deviceNo) { |
| | | if (wrkMast == null || wrkMast.getWrkNo() == null) { |
| | | return; |
| | | } |
| | | wrkMast.setWrkSts(WrkStsType.STATION_RUN_COMPLETE.sts); |
| | | wrkMast.setIoTime(new Date()); |
| | | wrkMastService.updateById(wrkMast); |
| | | if (deviceNo != null) { |
| | | notifyUtils.notify(String.valueOf(SlaveType.Devp), deviceNo, String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.STATION_OUT_TASK_RUN_COMPLETE, null); |
| | | } |
| | | redisUtil.set(RedisKeyType.STATION_OUT_EXECUTE_COMPLETE_LIMIT.key + wrkMast.getWrkNo(), "lock", 60); |
| | | } |
| | | |
| | | // 检测任务转完成 |
| | |
| | | continue; |
| | | } |
| | | |
| | | StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), moveStaNo, 0); |
| | | StationCommand command = stationThread.getRunBlockRerouteCommand( |
| | | wrkMast.getWrkNo(), |
| | | stationProtocol.getStationId(), |
| | | moveStaNo, |
| | | 0 |
| | | ); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败"); |
| | | News.taskInfo(wrkMast.getWrkNo(), |
| | | "输送站点堵塞重规划未找到可下发路线,当前站点={},目标站点={}", |
| | | stationProtocol.getStationId(), |
| | | moveStaNo); |
| | | continue; |
| | | } |
| | | |
| | |
| | | //获取输送线任务数量 |
| | | public synchronized int getCurrentStationTaskCount() { |
| | | return countCurrentStationTask(); |
| | | } |
| | | |
| | | public synchronized int getCurrentOutboundTaskCountByTargetStation(Integer stationId) { |
| | | if (stationId == null) { |
| | | return 0; |
| | | } |
| | | return (int) wrkMastService.count(new QueryWrapper<WrkMast>() |
| | | .eq("io_type", WrkIoType.OUT.id) |
| | | .eq("sta_no", stationId) |
| | | .in("wrk_sts", |
| | | WrkStsType.OUTBOUND_RUN.sts, |
| | | WrkStsType.OUTBOUND_RUN_COMPLETE.sts, |
| | | WrkStsType.STATION_RUN.sts)); |
| | | } |
| | | |
| | | // 检测出库排序 |
| | |
| | | if (!shouldApplyOutOrder(wrkMast, outOrderStationIds)) { |
| | | return new OutOrderDispatchDecision(wrkMast.getStaNo(), false); |
| | | } |
| | | Integer dispatchStationId = resolveDispatchOutOrderTarget( |
| | | wrkMast.getSourceStaNo(), |
| | | wrkMast.getStaNo(), |
| | | outOrderStationIds |
| | | ); |
| | | if (dispatchStationId == null) { |
| | | return null; |
| | | } |
| | | if (isCurrentOutOrderDispatchStation(currentStationId, wrkMast, outOrderStationIds)) { |
| | | return resolveCurrentOutOrderDispatchDecision(currentStationId, wrkMast, outOrderStationIds); |
| | | } |
| | | |
| | | Integer moveStaNo = resolveDispatchOutOrderTarget(currentStationId, wrkMast.getStaNo(), outOrderStationIds, true); |
| | | if (moveStaNo == null) { |
| | | return null; |
| | | if (!Objects.equals(dispatchStationId, wrkMast.getStaNo()) |
| | | && isCurrentOutOrderStation(currentStationId, outOrderStationIds) |
| | | && isWatchingCircleArrival(wrkMast.getWrkNo(), currentStationId)) { |
| | | return new OutOrderDispatchDecision(dispatchStationId, true); |
| | | } |
| | | return new OutOrderDispatchDecision(moveStaNo, false); |
| | | return new OutOrderDispatchDecision(dispatchStationId, false); |
| | | } |
| | | |
| | | private OutOrderDispatchDecision resolveCurrentOutOrderDispatchDecision(Integer currentStationId, |
| | |
| | | if (seq == null) { |
| | | toTarget = currentBatchSeq.equals(wrkMast.getBatchSeq()); |
| | | } else { |
| | | toTarget = Integer.valueOf(seq + 1).equals(wrkMast.getBatchSeq()) |
| | | && currentBatchSeq.equals(wrkMast.getBatchSeq()); |
| | | toTarget = Integer.valueOf(seq + 1).equals(wrkMast.getBatchSeq()); |
| | | } |
| | | if (toTarget) { |
| | | return new OutOrderDispatchDecision(wrkMast.getStaNo(), false); |
| | | if (hasReachableOutReleaseSlot(currentStationId, wrkMast.getStaNo())) { |
| | | return new OutOrderDispatchDecision(wrkMast.getStaNo(), false); |
| | | } |
| | | Integer circleTarget = resolveNextCircleOrderTarget(currentStationId, outOrderStationIds); |
| | | if (circleTarget == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "目标站当前不可进,且未找到可执行的下一排序检测点,当前站点={}", currentStationId); |
| | | return null; |
| | | } |
| | | return new OutOrderDispatchDecision(circleTarget, true); |
| | | } |
| | | |
| | | Integer circleTarget = resolveNextCircleOrderTarget(currentStationId, outOrderStationIds); |
| | |
| | | private boolean isCurrentOutOrderDispatchStation(Integer currentStationId, |
| | | WrkMast wrkMast, |
| | | List<Integer> outOrderStationIds) { |
| | | if (!shouldApplyOutOrder(wrkMast, outOrderStationIds) || currentStationId == null) { |
| | | return false; |
| | | } |
| | | Integer dispatchStationId = resolveDispatchOutOrderTarget( |
| | | wrkMast.getSourceStaNo(), |
| | | wrkMast.getStaNo(), |
| | | outOrderStationIds |
| | | ); |
| | | return dispatchStationId != null |
| | | && !Objects.equals(dispatchStationId, wrkMast.getStaNo()) |
| | | && Objects.equals(currentStationId, dispatchStationId); |
| | | } |
| | | |
| | | private boolean isCurrentOutOrderStation(Integer currentStationId, |
| | | List<Integer> outOrderStationIds) { |
| | | return currentStationId != null |
| | | && shouldApplyOutOrder(wrkMast, outOrderStationIds) |
| | | && !Objects.equals(currentStationId, wrkMast.getStaNo()) |
| | | && outOrderStationIds != null |
| | | && outOrderStationIds.contains(currentStationId); |
| | | } |
| | | |
| | |
| | | List<Integer> outOrderStationIds, |
| | | OutOrderDispatchDecision dispatchDecision, |
| | | StationCommand command) { |
| | | if (dispatchDecision == null || command == null) { |
| | | return; |
| | | } |
| | | if (!isCurrentOutOrderDispatchStation(currentStationId, wrkMast, outOrderStationIds)) { |
| | | if (dispatchDecision == null || command == null || !shouldApplyOutOrder(wrkMast, outOrderStationIds)) { |
| | | return; |
| | | } |
| | | if (dispatchDecision.isCircle()) { |
| | |
| | | } |
| | | } |
| | | |
| | | private Integer resolveDispatchOutOrderTarget(Integer currentStationId, |
| | | private Integer resolveDispatchOutOrderTarget(Integer sourceStationId, |
| | | Integer finalTargetStationId, |
| | | List<Integer> outOrderList, |
| | | boolean skipCurrentStation) { |
| | | List<Integer> outOrderList) { |
| | | if (finalTargetStationId == null) { |
| | | return null; |
| | | } |
| | | if (currentStationId == null || outOrderList == null || outOrderList.isEmpty()) { |
| | | if (sourceStationId == null || outOrderList == null || outOrderList.isEmpty()) { |
| | | return finalTargetStationId; |
| | | } |
| | | |
| | | try { |
| | | List<NavigateNode> nodes = navigateUtils.calcByStationId(currentStationId, finalTargetStationId); |
| | | List<NavigateNode> nodes = navigateUtils.calcByStationId(sourceStationId, finalTargetStationId); |
| | | for (int i = nodes.size() - 1; i >= 0; i--) { |
| | | Integer stationId = getStationIdFromNode(nodes.get(i)); |
| | | if (stationId == null) { |
| | | continue; |
| | | } |
| | | if (skipCurrentStation && currentStationId.equals(stationId)) { |
| | | if (Objects.equals(stationId, finalTargetStationId)) { |
| | | continue; |
| | | } |
| | | if (outOrderList.contains(stationId)) { |
| | |
| | | } |
| | | } catch (Exception ignore) {} |
| | | return finalTargetStationId; |
| | | } |
| | | |
| | | private boolean hasReachableOutReleaseSlot(Integer currentStationId, |
| | | Integer finalTargetStationId) { |
| | | if (currentStationId == null || finalTargetStationId == null) { |
| | | return true; |
| | | } |
| | | |
| | | try { |
| | | List<NavigateNode> nodes = navigateUtils.calcByStationId(currentStationId, finalTargetStationId); |
| | | if (nodes == null || nodes.isEmpty()) { |
| | | return true; |
| | | } |
| | | |
| | | for (NavigateNode node : nodes) { |
| | | Integer stationId = getStationIdFromNode(node); |
| | | if (stationId == null || Objects.equals(stationId, currentStationId)) { |
| | | continue; |
| | | } |
| | | |
| | | if (!isPathStationBlocked(stationId)) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } catch (Exception ignore) { |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | private boolean isPathStationBlocked(Integer stationId) { |
| | | if (stationId == null) { |
| | | return true; |
| | | } |
| | | |
| | | BasStation basStation = basStationService.getOne(new QueryWrapper<BasStation>().eq("station_id", stationId)); |
| | | if (basStation == null) { |
| | | return true; |
| | | } |
| | | |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basStation.getDeviceNo()); |
| | | if (stationThread == null) { |
| | | return true; |
| | | } |
| | | |
| | | StationProtocol stationProtocol = stationThread.getStatusMap().get(stationId); |
| | | if (stationProtocol == null) { |
| | | return true; |
| | | } |
| | | |
| | | return !stationProtocol.isAutoing() |
| | | || stationProtocol.isLoading() |
| | | || (stationProtocol.getTaskNo() != null && stationProtocol.getTaskNo() > 0); |
| | | } |
| | | |
| | | private Integer resolveNextCircleOrderTarget(Integer currentStationId, List<Integer> orderedOutStationList) { |
| | |
| | | return; |
| | | } |
| | | |
| | | if (hasFollowUpMoveCommandAfterStay(idleTrack, stationProtocol.getTaskNo(), stationProtocol.getStationId())) { |
| | | return; |
| | | } |
| | | |
| | | OutOrderDispatchDecision dispatchDecision = null; |
| | | Integer moveStaNo; |
| | | if (Objects.equals(wrkMast.getWrkSts(), WrkStsType.STATION_RUN.sts)) { |
| | |
| | | } |
| | | |
| | | redisUtil.set(RedisKeyType.CHECK_STATION_IDLE_RECOVER_LIMIT_.key + stationProtocol.getTaskNo(), "lock", STATION_IDLE_RECOVER_LIMIT_SECONDS); |
| | | resetSegmentMoveCommandsBeforeReroute(stationProtocol.getTaskNo()); |
| | | int clearedCommandCount = clearIssuedMoveCommandsDuringIdleStay(idleTrack, stationProtocol.getTaskNo(), stationProtocol.getStationId()); |
| | | |
| | | StationCommand command = stationThread.getCommand( |
| | | StationCommandType.MOVE, |
| | |
| | | MessageQueue.offer(SlaveType.Devp, basDevp.getDevpNo(), new Task(2, command)); |
| | | syncOutOrderWatchState(wrkMast, stationProtocol.getStationId(), outOrderList, dispatchDecision, command); |
| | | saveStationTaskIdleTrack(new StationTaskIdleTrack(wrkMast.getWrkNo(), stationProtocol.getStationId(), System.currentTimeMillis())); |
| | | News.info("输送站点任务停留{}秒未运行,已重新计算路径并重启运行,站点号={},目标站={},工作号={},命令数据={}", |
| | | STATION_IDLE_RECOVER_SECONDS, stationProtocol.getStationId(), moveStaNo, wrkMast.getWrkNo(), JSON.toJSONString(command)); |
| | | News.info("输送站点任务停留{}秒未运行,已重新计算路径并重启运行,站点号={},目标站={},工作号={},清理旧分段命令数={},命令数据={}", |
| | | STATION_IDLE_RECOVER_SECONDS, stationProtocol.getStationId(), moveStaNo, wrkMast.getWrkNo(), clearedCommandCount, JSON.toJSONString(command)); |
| | | } |
| | | |
| | | private boolean canRecoverIdleStationTask(WrkMast wrkMast, Integer currentStationId) { |
| | |
| | | || Objects.equals(wrkMast.getWrkSts(), WrkStsType.STATION_RUN.sts); |
| | | } |
| | | |
| | | private boolean hasFollowUpMoveCommandAfterStay(StationTaskIdleTrack idleTrack, |
| | | Integer taskNo, |
| | | Integer stationId) { |
| | | if (idleTrack == null || taskNo == null || stationId == null || idleTrack.firstSeenTime == null) { |
| | | return false; |
| | | private void resetSegmentMoveCommandsBeforeReroute(Integer taskNo) { |
| | | if (redisUtil == null || taskNo == null || taskNo <= 0) { |
| | | return; |
| | | } |
| | | if (basStationOptService == null) { |
| | | return false; |
| | | String key = RedisKeyType.DEVICE_STATION_MOVE_RESET.key + taskNo; |
| | | redisUtil.set(key, "cancel", 3); |
| | | try { |
| | | Thread.sleep(STATION_MOVE_RESET_WAIT_MS); |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | } catch (Exception ignore) { |
| | | } |
| | | redisUtil.del(key); |
| | | } |
| | | |
| | | private int clearIssuedMoveCommandsDuringIdleStay(StationTaskIdleTrack idleTrack, |
| | | Integer taskNo, |
| | | Integer stationId) { |
| | | if (basStationOptService == null) { |
| | | return 0; |
| | | } |
| | | List<BasStationOpt> optList; |
| | | try { |
| | | optList = basStationOptService.list(new QueryWrapper<BasStationOpt>() |
| | | .select("id", "target_station_id") |
| | | .eq("task_no", taskNo) |
| | | .eq("source_station_id", stationId) |
| | | .eq("mode", String.valueOf(StationCommandType.MOVE)) |
| | | .eq("send", 1) |
| | | .ge("send_time", new Date(idleTrack.firstSeenTime)) |
| | | .orderByDesc("send_time") |
| | | .last("limit 3")); |
| | | optList = listIssuedMoveCommandsDuringIdleStay(idleTrack, taskNo); |
| | | } catch (Exception e) { |
| | | return false; |
| | | return 0; |
| | | } |
| | | |
| | | if (optList == null || optList.isEmpty()) { |
| | | return false; |
| | | return 0; |
| | | } |
| | | |
| | | Date now = new Date(); |
| | | String cleanupMemo = buildIdleRecoverClearedMemo(stationId); |
| | | int clearedCount = 0; |
| | | for (BasStationOpt opt : optList) { |
| | | if (opt != null && opt.getTargetStationId() != null && !Objects.equals(opt.getTargetStationId(), stationId)) { |
| | | return true; |
| | | if (opt == null || opt.getId() == null) { |
| | | continue; |
| | | } |
| | | opt.setSend(0); |
| | | opt.setUpdateTime(now); |
| | | opt.setMemo(appendCleanupMemo(opt.getMemo(), cleanupMemo)); |
| | | clearedCount++; |
| | | } |
| | | return false; |
| | | if (clearedCount > 0) { |
| | | basStationOptService.updateBatchById(optList); |
| | | } |
| | | return clearedCount; |
| | | } |
| | | |
| | | private List<BasStationOpt> listIssuedMoveCommandsDuringIdleStay(StationTaskIdleTrack idleTrack, |
| | | Integer taskNo) { |
| | | if (idleTrack == null || taskNo == null || taskNo <= 0 || idleTrack.firstSeenTime == null || basStationOptService == null) { |
| | | return Collections.emptyList(); |
| | | } |
| | | List<BasStationOpt> optList = basStationOptService.list(new QueryWrapper<BasStationOpt>() |
| | | .select("id", "task_no", "send_time", "target_station_id", "memo", "send") |
| | | .eq("task_no", taskNo) |
| | | .eq("mode", String.valueOf(StationCommandType.MOVE)) |
| | | .eq("send", 1) |
| | | .ge("send_time", new Date(idleTrack.firstSeenTime)) |
| | | .orderByAsc("send_time")); |
| | | if (optList == null || optList.isEmpty()) { |
| | | return Collections.emptyList(); |
| | | } |
| | | return optList; |
| | | } |
| | | |
| | | private String buildIdleRecoverClearedMemo(Integer stationId) { |
| | | if (stationId == null) { |
| | | return IDLE_RECOVER_CLEARED_MEMO; |
| | | } |
| | | return IDLE_RECOVER_CLEARED_MEMO + "(stationId=" + stationId + ")"; |
| | | } |
| | | |
| | | private String appendCleanupMemo(String memo, String cleanupMemo) { |
| | | if (Cools.isEmpty(cleanupMemo)) { |
| | | return memo; |
| | | } |
| | | if (Cools.isEmpty(memo)) { |
| | | return cleanupMemo; |
| | | } |
| | | if (memo.contains(cleanupMemo)) { |
| | | return memo; |
| | | } |
| | | return memo + " | " + cleanupMemo; |
| | | } |
| | | |
| | | private StationTaskIdleTrack touchStationTaskIdleTrack(Integer taskNo, Integer stationId) { |