| | |
| | | import java.util.Arrays; |
| | | |
| | | public class ZyStationFakeSegConnect implements ZyStationConnectApi { |
| | | private static final long DEFAULT_FAKE_RUN_BLOCK_TIMEOUT_MS = 10000L; |
| | | |
| | | // 站点级锁:每个站点独立一把锁,提升并发性能 |
| | | private final Map<Integer, ReentrantLock> stationLocks = new ConcurrentHashMap<>(); |
| | |
| | | boolean initialized = false; |
| | | // 上一步执行时间(用于堵塞检测) |
| | | long stepExecuteTime = System.currentTimeMillis(); |
| | | long runBlockTimeoutMs = getFakeRunBlockTimeoutMs(); |
| | | // 仅在每次到达目标时执行一次到位处理,避免重复生成条码 |
| | | boolean arrivalHandled = false; |
| | | |
| | | while (true) { |
| | | if (Thread.currentThread().isInterrupted()) { |
| | |
| | | StationCommand command = commandQueue.poll(100, TimeUnit.MILLISECONDS); |
| | | if (command != null) { |
| | | taskLastUpdateTime.put(taskNo, System.currentTimeMillis()); |
| | | List<Integer> newPath = command.getNavigatePath(); |
| | | Integer lastInQueue = getLastInQueue(pendingPathQueue); |
| | | int startIndex = getPathAppendStartIndex(newPath, currentStationId, lastInQueue); |
| | | |
| | | if (newPath != null && !newPath.isEmpty() && startIndex < 0) { |
| | | News.info("[WCS Debug] 任务{}忽略无法衔接的旧路径段: {}, 当前位置: {}, 队列尾: {}", taskNo, |
| | | newPath, currentStationId, lastInQueue); |
| | | continue; |
| | | } |
| | | |
| | | // 每次接收命令都刷新目标,避免沿用旧目标导致状态抖动 |
| | | Integer commandTargetStationId = command.getTargetStaNo(); |
| | | if (commandTargetStationId != null) { |
| | | if (!commandTargetStationId.equals(finalTargetStationId)) { |
| | | arrivalHandled = false; |
| | | News.info("[WCS Debug] 任务{}切换目标: {} -> {}", taskNo, finalTargetStationId, |
| | | commandTargetStationId); |
| | | } |
| | |
| | | } |
| | | |
| | | // 将新路径追加到待执行队列 |
| | | List<Integer> newPath = command.getNavigatePath(); |
| | | if (newPath != null && !newPath.isEmpty()) { |
| | | // 获取队列中最后一个站点(用于衔接点去重) |
| | | Integer lastInQueue = getLastInQueue(pendingPathQueue); |
| | | int startIndex = getPathAppendStartIndex(newPath, currentStationId, lastInQueue); |
| | | |
| | | for (int i = startIndex; i < newPath.size(); i++) { |
| | | pendingPathQueue.offer(newPath.get(i)); |
| | | } |
| | |
| | | currentStationId = nextStationId; |
| | | pendingPathQueue.poll(); |
| | | stepExecuteTime = System.currentTimeMillis(); |
| | | arrivalHandled = false; |
| | | News.info("[WCS Debug] 任务{}移动到站点: {}, 剩余队列: {}", taskNo, currentStationId, |
| | | pendingPathQueue.size()); |
| | | sleep(1000); // 模拟移动耗时 |
| | |
| | | if (!checkTaskNoInArea(taskNo)) { |
| | | boolean fakeAllowCheckBlock = getFakeAllowCheckBlock(); |
| | | |
| | | if (fakeAllowCheckBlock && System.currentTimeMillis() - stepExecuteTime > 10000) { |
| | | if (fakeAllowCheckBlock |
| | | && System.currentTimeMillis() - stepExecuteTime > runBlockTimeoutMs) { |
| | | // 认定堵塞 |
| | | boolean result = runBlockStation(taskNo, currentStationId, currentDeviceNo, taskNo, |
| | | currentStationId); |
| | |
| | | // 路径队列为空,等待新的分段命令 |
| | | if (currentStationId != null && finalTargetStationId != null |
| | | && currentStationId.equals(finalTargetStationId)) { |
| | | // 已到达目标:立即清空当前队列并结束本轮执行,后续新命令重新创建执行线程 |
| | | if (generateBarcode) { |
| | | Integer targetDeviceNo = getDeviceNoByStationId(finalTargetStationId); |
| | | if (targetDeviceNo != null) { |
| | | generateStationBarcode(taskNo, finalTargetStationId, targetDeviceNo); |
| | | News.info("[WCS Debug] 任务{}到达目标{}并生成条码", taskNo, finalTargetStationId); |
| | | // 已到达当前目标后继续等待下一条分段命令,避免排序/绕圈场景吞掉后续命令 |
| | | if (!arrivalHandled) { |
| | | if (generateBarcode) { |
| | | Integer targetDeviceNo = getDeviceNoByStationId(finalTargetStationId); |
| | | if (targetDeviceNo != null) { |
| | | generateStationBarcode(taskNo, finalTargetStationId, targetDeviceNo); |
| | | News.info("[WCS Debug] 任务{}到达目标{}并生成条码", taskNo, finalTargetStationId); |
| | | } |
| | | } |
| | | arrivalHandled = true; |
| | | } |
| | | commandQueue.clear(); |
| | | pendingPathQueue.clear(); |
| | | News.info("[WCS Debug] 任务{}到达目标后清空队列并结束,等待后续新命令重启", taskNo); |
| | | break; |
| | | } |
| | | |
| | | // 继续等待新的分段命令 |
| | |
| | | if (idx >= 0) { |
| | | return idx + 1; |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | if (lastInQueue != null) { |
| | | return -1; |
| | | } |
| | | |
| | | return 0; |
| | |
| | | return fakeAllowCheckBlock; |
| | | } |
| | | |
| | | private long getFakeRunBlockTimeoutMs() { |
| | | long timeoutMs = DEFAULT_FAKE_RUN_BLOCK_TIMEOUT_MS; |
| | | Object systemConfigMapObj = redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key); |
| | | if (systemConfigMapObj instanceof Map) { |
| | | Map<?, ?> systemConfigMap = (Map<?, ?>) systemConfigMapObj; |
| | | Object value = systemConfigMap.get("fakeRunBlockTimeoutMs"); |
| | | if (value != null) { |
| | | try { |
| | | long parsed = Long.parseLong(String.valueOf(value).trim()); |
| | | if (parsed > 0) { |
| | | timeoutMs = parsed; |
| | | } |
| | | } catch (Exception ignore) { |
| | | } |
| | | } |
| | | } |
| | | return timeoutMs; |
| | | } |
| | | |
| | | @Override |
| | | public CommandResponse sendOriginCommand(String address, short[] data) { |
| | | return new CommandResponse(true, "原始命令已受理(异步执行)"); |