| | |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.alibaba.fastjson.serializer.SerializerFeature; |
| | | import com.baomidou.mybatisplus.mapper.EntityWrapper; |
| | | import com.core.common.Cools; |
| | | import com.core.exception.CoolException; |
| | | import com.zy.asrs.domain.enums.NotifyMsgType; |
| | | import com.zy.asrs.domain.vo.StationCycleCapacityVo; |
| | | import com.zy.asrs.domain.vo.StationCycleLoopVo; |
| | | import com.zy.asrs.entity.*; |
| | | import com.zy.asrs.service.*; |
| | | import com.zy.asrs.utils.NotifyUtils; |
| | | 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.MessageQueue; |
| | |
| | | |
| | | @Component |
| | | public class StationOperateProcessUtils { |
| | | private static final int LOOP_LOAD_RESERVE_EXPIRE_SECONDS = 120; |
| | | |
| | | @Autowired |
| | | private BasDevpService basDevpService; |
| | |
| | | @Autowired |
| | | private CommonService commonService; |
| | | @Autowired |
| | | private BasCrnpService basCrnpService; |
| | | @Autowired |
| | | private BasDualCrnpService basDualCrnpService; |
| | | @Autowired |
| | | private RedisUtil redisUtil; |
| | | @Autowired |
| | | private LocMastService locMastService; |
| | | @Autowired |
| | | private WmsOperateUtils wmsOperateUtils; |
| | | @Autowired |
| | | private NotifyUtils notifyUtils; |
| | | @Autowired |
| | | private NavigateUtils navigateUtils; |
| | | @Autowired |
| | | private BasStationService basStationService; |
| | | @Autowired |
| | | private StationCycleCapacityService stationCycleCapacityService; |
| | | |
| | | //执行输送站点入库任务 |
| | | public synchronized void stationInExecute() { |
| | | try { |
| | | DispatchLimitConfig limitConfig = getDispatchLimitConfig(); |
| | | int[] currentStationTaskCountRef = new int[]{countCurrentStationTask()}; |
| | | LoadGuardState loadGuardState = buildLoadGuardState(limitConfig); |
| | | |
| | | List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<>()); |
| | | for (BasDevp basDevp : basDevps) { |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo()); |
| | |
| | | continue; |
| | | } |
| | | |
| | | LoopHitResult loopHitResult = findPathLoopHit(limitConfig, stationProtocol.getStationId(), targetStationId, loadGuardState); |
| | | |
| | | if (isDispatchBlocked(limitConfig, currentStationTaskCountRef[0], loadGuardState, loopHitResult.isThroughLoop())) { |
| | | return; |
| | | } |
| | | |
| | | StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationId, targetStationId, 0); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "{}工作,获取输送线命令失败", wrkMast.getWrkNo()); |
| | |
| | | MessageQueue.offer(SlaveType.Devp, basDevp.getDevpNo(), new Task(2, command)); |
| | | News.info("输送站点入库命令下发成功,站点号={},工作号={},命令数据={}", stationId, wrkMast.getWrkNo(), JSON.toJSONString(command)); |
| | | redisUtil.set(RedisKeyType.STATION_IN_EXECUTE_LIMIT.key + stationId, "lock", 5); |
| | | loadGuardState.reserveLoopTask(loopHitResult.getLoopNo()); |
| | | saveLoopLoadReserve(wrkMast.getWrkNo(), loopHitResult); |
| | | } |
| | | } |
| | | } |
| | |
| | | //执行堆垛机输送站点出库任务 |
| | | public synchronized void crnStationOutExecute() { |
| | | try { |
| | | DispatchLimitConfig limitConfig = getDispatchLimitConfig(); |
| | | int[] currentStationTaskCountRef = new int[]{countCurrentStationTask()}; |
| | | LoadGuardState loadGuardState = buildLoadGuardState(limitConfig); |
| | | |
| | | List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>() |
| | | .eq("wrk_sts", WrkStsType.OUTBOUND_RUN_COMPLETE.sts) |
| | | .isNotNull("crn_no") |
| | | ); |
| | | List<Integer> outOrderList = getAllOutOrderList(); |
| | | |
| | | for (WrkMast wrkMast : wrkMasts) { |
| | | Object infoObj = redisUtil.get(RedisKeyType.CRN_OUT_TASK_COMPLETE_STATION_INFO.key + wrkMast.getWrkNo()); |
| | | if (infoObj == null) { |
| | |
| | | && stationProtocol.isLoading() |
| | | && stationProtocol.getTaskNo() == 0 |
| | | ) { |
| | | StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), wrkMast.getStaNo(), 0); |
| | | Integer moveStaNo = wrkMast.getStaNo(); |
| | | |
| | | if (!outOrderList.isEmpty()) { |
| | | List<NavigateNode> nodes = navigateUtils.calcByStationId(stationProtocol.getStationId(), wrkMast.getStaNo()); |
| | | for (int i = nodes.size() - 1; i >= 0; i--) { |
| | | NavigateNode node = nodes.get(i); |
| | | JSONObject v = JSONObject.parseObject(node.getNodeValue()); |
| | | if (v != null) { |
| | | Integer stationId = v.getInteger("stationId"); |
| | | if (outOrderList.contains(stationId)) { |
| | | moveStaNo = stationId; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | LoopHitResult loopHitResult = findPathLoopHit(limitConfig, stationProtocol.getStationId(), moveStaNo, loadGuardState); |
| | | |
| | | if (isDispatchBlocked(limitConfig, currentStationTaskCountRef[0], loadGuardState, loopHitResult.isThroughLoop())) { |
| | | return; |
| | | } |
| | | |
| | | StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), moveStaNo, 0); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败"); |
| | | continue; |
| | |
| | | MessageQueue.offer(SlaveType.Devp, stationObjModel.getDeviceNo(), new Task(2, command)); |
| | | News.info("输送站点出库命令下发成功,站点号={},工作号={},命令数据={}", stationProtocol.getStationId(), wrkMast.getWrkNo(), JSON.toJSONString(command)); |
| | | redisUtil.set(RedisKeyType.STATION_OUT_EXECUTE_LIMIT.key + stationProtocol.getStationId(), "lock", 5); |
| | | redisUtil.set(RedisKeyType.STATION_OUT_EXECUTE_COMPLETE_LIMIT.key + wrkMast.getWrkNo(), "lock", 60); |
| | | redisUtil.del(RedisKeyType.CRN_OUT_TASK_COMPLETE_STATION_INFO.key + wrkMast.getWrkNo()); |
| | | currentStationTaskCountRef[0]++; |
| | | loadGuardState.reserveLoopTask(loopHitResult.getLoopNo()); |
| | | saveLoopLoadReserve(wrkMast.getWrkNo(), loopHitResult); |
| | | } |
| | | } |
| | | } |
| | |
| | | wrkMast.setIoTime(new Date()); |
| | | if (wrkMastService.updateById(wrkMast)) { |
| | | MessageQueue.offer(SlaveType.Devp, stationObjModel.getDeviceNo(), new Task(2, command)); |
| | | notifyUtils.notify(String.valueOf(SlaveType.Devp), stationObjModel.getDeviceNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.STATION_OUT_TASK_RUN, null); |
| | | News.info("输送站点出库命令下发成功,站点号={},工作号={},命令数据={}", stationProtocol.getStationId(), wrkMast.getWrkNo(), JSON.toJSONString(command)); |
| | | redisUtil.set(RedisKeyType.STATION_OUT_EXECUTE_LIMIT.key + stationProtocol.getStationId(), "lock", 5); |
| | | redisUtil.set(RedisKeyType.STATION_OUT_EXECUTE_COMPLETE_LIMIT.key + wrkMast.getWrkNo(), "lock", 60); |
| | | redisUtil.del(RedisKeyType.DUAL_CRN_OUT_TASK_STATION_INFO.key + wrkMast.getWrkNo()); |
| | | } |
| | | } |
| | |
| | | List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>().eq("wrk_sts", WrkStsType.STATION_RUN.sts)); |
| | | for (WrkMast wrkMast : wrkMasts) { |
| | | Integer wrkNo = wrkMast.getWrkNo(); |
| | | Integer targetStaNo = wrkMast.getStaNo(); |
| | | |
| | | boolean complete = false; |
| | | BasStation basStation = basStationService.selectOne(new EntityWrapper<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 (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); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | // 检测任务转完成 |
| | | public synchronized void checkTaskToComplete() { |
| | | try { |
| | | List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>().eq("wrk_sts", WrkStsType.STATION_RUN_COMPLETE.sts)); |
| | | for (WrkMast wrkMast : wrkMasts) { |
| | | Integer wrkNo = wrkMast.getWrkNo(); |
| | | Integer targetStaNo = wrkMast.getStaNo(); |
| | | |
| | | Object lock = redisUtil.get(RedisKeyType.STATION_OUT_EXECUTE_COMPLETE_LIMIT.key + wrkNo); |
| | | if (lock != null) { |
| | | continue; |
| | | } |
| | | |
| | | boolean complete = true; |
| | | List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<>()); |
| | | for (BasDevp basDevp : basDevps) { |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo()); |
| | | if (stationThread == null) { |
| | | continue; |
| | | } |
| | | boolean complete = false; |
| | | BasStation basStation = basStationService.selectOne(new EntityWrapper<BasStation>().eq("station_id", targetStaNo)); |
| | | if (basStation == null) { |
| | | continue; |
| | | } |
| | | |
| | | List<StationProtocol> list = stationThread.getStatus(); |
| | | for (StationProtocol stationProtocol : list) { |
| | | if (stationProtocol.getTaskNo().equals(wrkNo)) { |
| | | complete = false; |
| | | } |
| | | } |
| | | 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 (complete) { |
| | |
| | | |
| | | //获取输送线任务数量 |
| | | public synchronized int getCurrentStationTaskCount() { |
| | | int currentStationTaskCount = 0; |
| | | return countCurrentStationTask(); |
| | | } |
| | | |
| | | // 检测出库排序 |
| | | public synchronized void checkStationOutOrder() { |
| | | List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<BasDevp>()); |
| | | for (BasDevp basDevp : basDevps) { |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getId()); |
| | | if (stationThread == null) { |
| | | continue; |
| | | } |
| | | Map<Integer, StationProtocol> statusMap = stationThread.getStatusMap(); |
| | | List<StationObjModel> orderList = basDevp.getOutOrderList$(); |
| | | for (StationObjModel stationObjModel : orderList) { |
| | | StationProtocol stationProtocol = statusMap.get(stationObjModel.getStationId()); |
| | | if (stationProtocol == null) { |
| | | continue; |
| | | } |
| | | |
| | | if (!stationProtocol.isAutoing()) { |
| | | continue; |
| | | } |
| | | |
| | | if (!stationProtocol.isLoading()) { |
| | | continue; |
| | | } |
| | | |
| | | if (stationProtocol.getTaskNo() <= 0) { |
| | | continue; |
| | | } |
| | | |
| | | if (!stationProtocol.getStationId().equals(stationProtocol.getTargetStaNo())) { |
| | | continue; |
| | | } |
| | | |
| | | WrkMast wrkMast = wrkMastService.selectByWorkNo(stationProtocol.getTaskNo()); |
| | | if (wrkMast == null) { |
| | | continue; |
| | | } |
| | | |
| | | if (Cools.isEmpty(wrkMast.getBatch())) { |
| | | continue; |
| | | } |
| | | |
| | | if (Cools.isEmpty(wrkMast.getBatchSeq())) { |
| | | continue; |
| | | } |
| | | |
| | | List<WrkMast> batchWrkList = wrkMastService.selectList(new EntityWrapper<WrkMast>() |
| | | .notIn("wrk_sts", WrkStsType.STATION_RUN_COMPLETE.sts, WrkStsType.COMPLETE_OUTBOUND.sts) |
| | | .eq("batch", wrkMast.getBatch()) |
| | | .orderBy("batch") |
| | | ); |
| | | if (batchWrkList.isEmpty()) { |
| | | continue; |
| | | } |
| | | WrkMast firstWrkMast = batchWrkList.get(0); |
| | | Integer currentBatchSeq = firstWrkMast.getBatchSeq(); |
| | | |
| | | List<NavigateNode> initPath = navigateUtils.calcByStationId(wrkMast.getSourceStaNo(), wrkMast.getStaNo()); |
| | | |
| | | String commandType = "none"; |
| | | Integer seq = getOutStationBatchSeq(initPath, stationProtocol.getStationId(), wrkMast.getBatch()); |
| | | if (seq == null) { |
| | | if (currentBatchSeq.equals(wrkMast.getBatchSeq())) { |
| | | commandType = "toTarget"; |
| | | }else { |
| | | commandType = "toCircle"; |
| | | } |
| | | }else { |
| | | seq++; |
| | | if (seq.equals(wrkMast.getBatchSeq()) && currentBatchSeq.equals(wrkMast.getBatchSeq())) { |
| | | commandType = "toTarget"; |
| | | }else { |
| | | commandType = "toCircle"; |
| | | } |
| | | } |
| | | |
| | | if (commandType.equals("toTarget")) { |
| | | StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), wrkMast.getStaNo(), 0); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败"); |
| | | continue; |
| | | } |
| | | MessageQueue.offer(SlaveType.Devp, stationObjModel.getDeviceNo(), new Task(2, command)); |
| | | News.info("{}任务直接去目标点", wrkMast.getWrkNo()); |
| | | } else if (commandType.equals("toCircle")) { |
| | | Integer circleTarget = null; |
| | | for (NavigateNode node : initPath) { |
| | | JSONObject v = JSONObject.parseObject(node.getNodeValue()); |
| | | if (v != null) { |
| | | Integer stationId = v.getInteger("stationId"); |
| | | try { |
| | | List<NavigateNode> enableMovePath = navigateUtils.calcByStationId(stationProtocol.getStationId(), stationId); |
| | | if (enableMovePath.isEmpty()) { |
| | | continue; |
| | | } |
| | | } catch (Exception e) { |
| | | continue; |
| | | } |
| | | |
| | | circleTarget = stationId; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (circleTarget == null) { |
| | | continue; |
| | | } |
| | | |
| | | StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), circleTarget, 0); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败"); |
| | | continue; |
| | | } |
| | | MessageQueue.offer(SlaveType.Devp, stationObjModel.getDeviceNo(), new Task(2, command)); |
| | | redisUtil.set(RedisKeyType.WATCH_CIRCLE_STATION_.key + wrkMast.getWrkNo(), JSON.toJSONString(command, SerializerFeature.DisableCircularReferenceDetect), 60 * 60 * 24); |
| | | News.info("{}任务进行绕圈", wrkMast.getWrkNo()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 监控绕圈站点 |
| | | public synchronized void watchCircleStation() { |
| | | List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<BasDevp>()); |
| | | for (BasDevp basDevp : basDevps) { |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getId()); |
| | | if (stationThread == null) { |
| | | continue; |
| | | } |
| | | |
| | | List<Integer> outOrderList = basDevp.getOutOrderIntList(); |
| | | |
| | | for (StationProtocol stationProtocol : stationThread.getStatus()) { |
| | | if (!stationProtocol.isAutoing()) { |
| | | continue; |
| | | } |
| | | |
| | | if (!stationProtocol.isLoading()) { |
| | | continue; |
| | | } |
| | | |
| | | if (stationProtocol.getTaskNo() <= 0) { |
| | | continue; |
| | | } |
| | | |
| | | Object circleObj = redisUtil.get(RedisKeyType.WATCH_CIRCLE_STATION_.key + stationProtocol.getTaskNo()); |
| | | if (circleObj == null) { |
| | | continue; |
| | | } |
| | | |
| | | StationCommand circleCommand = JSON.parseObject(circleObj.toString(), StationCommand.class); |
| | | if (!stationProtocol.getStationId().equals(circleCommand.getTargetStaNo())) { |
| | | continue; |
| | | } |
| | | |
| | | WrkMast wrkMast = wrkMastService.selectByWorkNo(stationProtocol.getTaskNo()); |
| | | if (wrkMast == null) { |
| | | continue; |
| | | } |
| | | |
| | | Integer moveStaNo = wrkMast.getStaNo(); |
| | | |
| | | if (!outOrderList.isEmpty()) { |
| | | List<NavigateNode> nodes = navigateUtils.calcByStationId(stationProtocol.getStationId(), wrkMast.getStaNo()); |
| | | for (int i = nodes.size() - 1; i >= 0; i--) { |
| | | NavigateNode node = nodes.get(i); |
| | | JSONObject v = JSONObject.parseObject(node.getNodeValue()); |
| | | if (v != null) { |
| | | Integer stationId = v.getInteger("stationId"); |
| | | if (outOrderList.contains(stationId)) { |
| | | moveStaNo = stationId; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), moveStaNo, 0); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败"); |
| | | continue; |
| | | } |
| | | MessageQueue.offer(SlaveType.Devp, basDevp.getDevpNo(), new Task(2, command)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public List<Integer> getAllOutOrderList() { |
| | | List<Integer> list = new ArrayList<>(); |
| | | List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<BasDevp>()); |
| | | for (BasDevp basDevp : basDevps) { |
| | | List<Integer> orderList = basDevp.getOutOrderIntList(); |
| | | list.addAll(orderList); |
| | | } |
| | | return list; |
| | | } |
| | | |
| | | public Integer getOutStationBatchSeq(List<NavigateNode> pathList, Integer searchStationId, String searchBatch) { |
| | | List<Integer> checkList = new ArrayList<>(); |
| | | for (int i = pathList.size() - 1; i >= 0; i--) { |
| | | NavigateNode node = pathList.get(i); |
| | | JSONObject v = JSONObject.parseObject(node.getNodeValue()); |
| | | if (v != null) { |
| | | Integer stationId = v.getInteger("stationId"); |
| | | if (searchStationId.equals(stationId)) { |
| | | break; |
| | | } else { |
| | | checkList.add(stationId); |
| | | } |
| | | } |
| | | } |
| | | |
| | | HashMap<String, Integer> batchMap = new HashMap<>(); |
| | | for (Integer station : checkList) { |
| | | BasStation basStation = basStationService.selectOne(new EntityWrapper<BasStation>().eq("station_id", station)); |
| | | if (basStation == null) { |
| | | continue; |
| | | } |
| | | |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basStation.getDeviceNo()); |
| | | if (stationThread == null) { |
| | | continue; |
| | | } |
| | | Map<Integer, StationProtocol> statusMap = stationThread.getStatusMap(); |
| | | StationProtocol checkStationProtocol = statusMap.get(station); |
| | | if (checkStationProtocol == null) { |
| | | continue; |
| | | } |
| | | if (checkStationProtocol.getTaskNo() > 0) { |
| | | WrkMast checkWrkMast = wrkMastService.selectByWorkNo(checkStationProtocol.getTaskNo()); |
| | | if (checkWrkMast == null) { |
| | | continue; |
| | | } |
| | | |
| | | if (!Cools.isEmpty(checkWrkMast.getBatch())) { |
| | | batchMap.put(checkWrkMast.getBatch(), checkWrkMast.getBatchSeq()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | Integer seq = batchMap.get(searchBatch); |
| | | return seq; |
| | | } |
| | | |
| | | private int countCurrentStationTask() { |
| | | int currentStationTaskCount = 0; |
| | | List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<BasDevp>()); |
| | | for (BasDevp basDevp : basDevps) { |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo()); |
| | | if (stationThread == null) { |
| | | continue; |
| | | } |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | return currentStationTaskCount; |
| | | } |
| | | |
| | | private boolean isDispatchBlocked(DispatchLimitConfig config, |
| | | int currentStationTaskCount, |
| | | LoadGuardState loadGuardState, |
| | | boolean needReserveLoopLoad) { |
| | | if (config.loopModeEnable) { |
| | | double currentLoad = loadGuardState.currentLoad(); |
| | | if (currentLoad >= config.circleMaxLoadLimit) { |
| | | News.warn("当前承载量达到上限,已停止站点任务下发。当前承载量={},上限={}", formatPercent(currentLoad), formatPercent(config.circleMaxLoadLimit)); |
| | | return true; |
| | | } |
| | | |
| | | if (needReserveLoopLoad) { |
| | | double reserveLoad = loadGuardState.loadAfterReserve(); |
| | | if (reserveLoad >= config.circleMaxLoadLimit) { |
| | | News.warn("预占后承载量达到上限,已停止站点任务下发。预占后承载量={},上限={}", formatPercent(reserveLoad), formatPercent(config.circleMaxLoadLimit)); |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (config.stationMaxTaskCount > 0 && currentStationTaskCount >= config.stationMaxTaskCount) { |
| | | News.warn("输送站点任务数量达到上限,已停止站点任务下发。当前任务数={},上限={}", currentStationTaskCount, config.stationMaxTaskCount); |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | private LoadGuardState buildLoadGuardState(DispatchLimitConfig config) { |
| | | LoadGuardState state = new LoadGuardState(); |
| | | if (!config.loopModeEnable) { |
| | | return state; |
| | | } |
| | | |
| | | StationCycleCapacityVo capacityVo = stationCycleCapacityService.getLatestSnapshot(); |
| | | if (capacityVo == null) { |
| | | return state; |
| | | } |
| | | |
| | | state.totalStationCount = toNonNegative(capacityVo.getTotalStationCount()); |
| | | state.projectedTaskStationCount = toNonNegative(capacityVo.getTaskStationCount()); |
| | | |
| | | List<StationCycleLoopVo> loopList = capacityVo.getLoopList(); |
| | | if (loopList != null) { |
| | | for (StationCycleLoopVo loopVo : loopList) { |
| | | if (loopVo == null || loopVo.getStationIdList() == null) { |
| | | continue; |
| | | } |
| | | Integer loopNo = loopVo.getLoopNo(); |
| | | for (Integer stationId : loopVo.getStationIdList()) { |
| | | if (stationId != null) { |
| | | if (loopNo != null) { |
| | | state.stationLoopNoMap.put(stationId, loopNo); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return state; |
| | | } |
| | | |
| | | private LoopHitResult findPathLoopHit(DispatchLimitConfig config, |
| | | Integer sourceStationId, |
| | | Integer targetStationId, |
| | | LoadGuardState loadGuardState) { |
| | | if (!config.loopModeEnable) { |
| | | return LoopHitResult.NO_HIT; |
| | | } |
| | | if (sourceStationId == null || targetStationId == null) { |
| | | return LoopHitResult.NO_HIT; |
| | | } |
| | | if (loadGuardState.stationLoopNoMap.isEmpty()) { |
| | | return LoopHitResult.NO_HIT; |
| | | } |
| | | |
| | | try { |
| | | List<NavigateNode> nodes = navigateUtils.calcByStationId(sourceStationId, targetStationId); |
| | | if (nodes == null || nodes.isEmpty()) { |
| | | return LoopHitResult.NO_HIT; |
| | | } |
| | | |
| | | for (NavigateNode node : nodes) { |
| | | Integer stationId = getStationIdFromNode(node); |
| | | if (stationId == null) { |
| | | continue; |
| | | } |
| | | Integer loopNo = loadGuardState.stationLoopNoMap.get(stationId); |
| | | if (loopNo != null) { |
| | | return new LoopHitResult(true, loopNo, stationId); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | return LoopHitResult.NO_HIT; |
| | | } |
| | | |
| | | return LoopHitResult.NO_HIT; |
| | | } |
| | | |
| | | private Integer getStationIdFromNode(NavigateNode node) { |
| | | if (node == null || isBlank(node.getNodeValue())) { |
| | | return null; |
| | | } |
| | | try { |
| | | JSONObject v = JSONObject.parseObject(node.getNodeValue()); |
| | | if (v == null) { |
| | | return null; |
| | | } |
| | | return v.getInteger("stationId"); |
| | | } catch (Exception e) { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | private int toNonNegative(Integer value) { |
| | | if (value == null || value < 0) { |
| | | return 0; |
| | | } |
| | | return value; |
| | | } |
| | | |
| | | private void saveLoopLoadReserve(Integer wrkNo, LoopHitResult loopHitResult) { |
| | | if (wrkNo == null || wrkNo <= 0 || loopHitResult == null || !loopHitResult.isThroughLoop()) { |
| | | return; |
| | | } |
| | | JSONObject reserveJson = new JSONObject(); |
| | | reserveJson.put("wrkNo", wrkNo); |
| | | reserveJson.put("loopNo", loopHitResult.getLoopNo()); |
| | | reserveJson.put("hitStationId", loopHitResult.getHitStationId()); |
| | | reserveJson.put("createTime", System.currentTimeMillis()); |
| | | redisUtil.hset(RedisKeyType.STATION_CYCLE_LOAD_RESERVE.key, String.valueOf(wrkNo), reserveJson.toJSONString()); |
| | | redisUtil.expire(RedisKeyType.STATION_CYCLE_LOAD_RESERVE.key, LOOP_LOAD_RESERVE_EXPIRE_SECONDS); |
| | | } |
| | | |
| | | private DispatchLimitConfig getDispatchLimitConfig() { |
| | | DispatchLimitConfig config = new DispatchLimitConfig(); |
| | | Object systemConfigMapObj = redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key); |
| | | if (!(systemConfigMapObj instanceof Map)) { |
| | | return config; |
| | | } |
| | | Map<?, ?> systemConfigMap = (Map<?, ?>) systemConfigMapObj; |
| | | |
| | | config.circleMaxLoadLimit = parseLoadLimit(getConfigValue(systemConfigMap, "circleMaxLoadLimit"), config.circleMaxLoadLimit); |
| | | String loopModeValue = getConfigValue(systemConfigMap, "circleLoopModeEnable"); |
| | | if (isBlank(loopModeValue)) { |
| | | loopModeValue = getConfigValue(systemConfigMap, "circleModeEnable"); |
| | | } |
| | | if (isBlank(loopModeValue)) { |
| | | loopModeValue = getConfigValue(systemConfigMap, "isCircleMode"); |
| | | } |
| | | config.loopModeEnable = parseBoolean(loopModeValue, config.loopModeEnable); |
| | | |
| | | String stationMaxTaskCountValue = getConfigValue(systemConfigMap, "stationMaxTaskCountLimit"); |
| | | if (isBlank(stationMaxTaskCountValue)) { |
| | | stationMaxTaskCountValue = getConfigValue(systemConfigMap, "stationMaxTaskCount"); |
| | | } |
| | | if (isBlank(stationMaxTaskCountValue)) { |
| | | stationMaxTaskCountValue = getConfigValue(systemConfigMap, "conveyorStationTaskLimit"); |
| | | } |
| | | config.stationMaxTaskCount = parseInt(stationMaxTaskCountValue, config.stationMaxTaskCount); |
| | | |
| | | return config; |
| | | } |
| | | |
| | | private String getConfigValue(Map<?, ?> configMap, String key) { |
| | | Object value = configMap.get(key); |
| | | if (value == null) { |
| | | return null; |
| | | } |
| | | return String.valueOf(value).trim(); |
| | | } |
| | | |
| | | private boolean parseBoolean(String value, boolean defaultValue) { |
| | | if (isBlank(value)) { |
| | | return defaultValue; |
| | | } |
| | | String lowValue = value.toLowerCase(Locale.ROOT); |
| | | if ("y".equals(lowValue) || "yes".equals(lowValue) || "true".equals(lowValue) |
| | | || "1".equals(lowValue) || "on".equals(lowValue)) { |
| | | return true; |
| | | } |
| | | if ("n".equals(lowValue) || "no".equals(lowValue) || "false".equals(lowValue) |
| | | || "0".equals(lowValue) || "off".equals(lowValue)) { |
| | | return false; |
| | | } |
| | | return defaultValue; |
| | | } |
| | | |
| | | private double parseLoadLimit(String value, double defaultValue) { |
| | | if (isBlank(value)) { |
| | | return defaultValue; |
| | | } |
| | | try { |
| | | String normalized = value.replace("%", "").trim(); |
| | | double parsed = Double.parseDouble(normalized); |
| | | if (parsed > 1.0) { |
| | | parsed = parsed / 100.0; |
| | | } |
| | | if (parsed < 0.0) { |
| | | return 0.0; |
| | | } |
| | | if (parsed > 1.0) { |
| | | return 1.0; |
| | | } |
| | | return parsed; |
| | | } catch (Exception e) { |
| | | return defaultValue; |
| | | } |
| | | } |
| | | |
| | | private int parseInt(String value, int defaultValue) { |
| | | if (isBlank(value)) { |
| | | return defaultValue; |
| | | } |
| | | try { |
| | | int parsed = Integer.parseInt(value.trim()); |
| | | return parsed < 0 ? defaultValue : parsed; |
| | | } catch (Exception e) { |
| | | return defaultValue; |
| | | } |
| | | } |
| | | |
| | | private String formatPercent(double value) { |
| | | return String.format(Locale.ROOT, "%.1f%%", value * 100.0); |
| | | } |
| | | |
| | | private boolean isBlank(String value) { |
| | | return value == null || value.trim().isEmpty(); |
| | | } |
| | | |
| | | private static class DispatchLimitConfig { |
| | | // 圈最大承载能力,默认80% |
| | | private double circleMaxLoadLimit = 0.8d; |
| | | // 是否启用绕圈模式(仅启用时才生效承载限制) |
| | | private boolean loopModeEnable = false; |
| | | // 站点最大任务数量上限,0表示不限制 |
| | | private int stationMaxTaskCount = 30; |
| | | } |
| | | |
| | | private static class LoadGuardState { |
| | | private int totalStationCount = 0; |
| | | private int projectedTaskStationCount = 0; |
| | | private final Map<Integer, Integer> stationLoopNoMap = new HashMap<>(); |
| | | |
| | | private double currentLoad() { |
| | | return calcLoad(this.projectedTaskStationCount, this.totalStationCount); |
| | | } |
| | | |
| | | private double loadAfterReserve() { |
| | | return calcLoad(this.projectedTaskStationCount + 1, this.totalStationCount); |
| | | } |
| | | |
| | | private void reserveLoopTask(Integer loopNo) { |
| | | if (loopNo == null || loopNo <= 0) { |
| | | return; |
| | | } |
| | | if (this.totalStationCount <= 0) { |
| | | return; |
| | | } |
| | | this.projectedTaskStationCount++; |
| | | } |
| | | |
| | | private double calcLoad(int taskCount, int stationCount) { |
| | | if (stationCount <= 0 || taskCount <= 0) { |
| | | return 0.0; |
| | | } |
| | | double load = (double) taskCount / (double) stationCount; |
| | | if (load < 0.0) { |
| | | return 0.0; |
| | | } |
| | | if (load > 1.0) { |
| | | return 1.0; |
| | | } |
| | | return load; |
| | | } |
| | | } |
| | | |
| | | private static class LoopHitResult { |
| | | private static final LoopHitResult NO_HIT = new LoopHitResult(false, null, null); |
| | | private final boolean throughLoop; |
| | | private final Integer loopNo; |
| | | private final Integer hitStationId; |
| | | |
| | | private LoopHitResult(boolean throughLoop, Integer loopNo, Integer hitStationId) { |
| | | this.throughLoop = throughLoop; |
| | | this.loopNo = loopNo; |
| | | this.hitStationId = hitStationId; |
| | | } |
| | | |
| | | private boolean isThroughLoop() { |
| | | return throughLoop; |
| | | } |
| | | |
| | | private Integer getLoopNo() { |
| | | return loopNo; |
| | | } |
| | | |
| | | private Integer getHitStationId() { |
| | | return hitStationId; |
| | | } |
| | | } |
| | | |
| | | } |