fix(ops): 修复工牌关机重启后工单状态不一致漏洞
问题场景: 1. 工牌有执行中工单(ARRIVED)后关机 2. 工牌重启,Redis状态丢失/过期,设备变为IDLE 3. 系统推送新工单 4. 信标检测仍在用旧工单配置,导致状态混乱 修复方案: 1. 派发新工单前检查并清理/取消旧工单残留 2. 设备离线时自动取消未完成的工单 3. 信标检测器增加工单切换检测,清理旧检测状态 涉及文件: - BadgeDeviceStatusEventListener: 增加旧工单清理和离线事件监听 - BadgeDeviceStatusServiceImpl: 设备离线时发布事件 - BeaconDetectionRuleProcessor: 工单切换检测 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,7 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 蓝牙信标检测规则处理器
|
||||
@@ -53,6 +54,12 @@ public class BeaconDetectionRuleProcessor {
|
||||
@Resource
|
||||
private RocketMQTemplate rocketMQTemplate;
|
||||
|
||||
/**
|
||||
* 上次检测的工单ID缓存(设备ID -> 工单ID)
|
||||
* 用于检测工单切换,清理旧工单的检测状态
|
||||
*/
|
||||
private final Map<Long, Long> lastDetectedOrderCache = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 处理蓝牙属性上报
|
||||
* <p>
|
||||
@@ -75,12 +82,27 @@ public class BeaconDetectionRuleProcessor {
|
||||
|
||||
if (currentOrder == null || currentOrder.getAreaId() == null) {
|
||||
log.debug("[BeaconDetection] 无当前工单,跳过检测:deviceId={}", deviceId);
|
||||
// 无工单时清理本地缓存
|
||||
lastDetectedOrderCache.remove(deviceId);
|
||||
return;
|
||||
}
|
||||
|
||||
Long areaId = currentOrder.getAreaId();
|
||||
Long orderId = currentOrder.getOrderId();
|
||||
|
||||
// 3. 检测工单切换,清理旧工单的检测状态
|
||||
Long lastOrderId = lastDetectedOrderCache.get(deviceId);
|
||||
if (lastOrderId != null && !lastOrderId.equals(orderId)) {
|
||||
log.warn("[BeaconDetection] 检测到工单切换,清理旧工单的检测状态: " +
|
||||
"deviceId={}, oldOrderId={}, newOrderId={}", deviceId, lastOrderId, orderId);
|
||||
// 清理旧的检测状态(清理当前设备的所有区域检测状态)
|
||||
cleanupAllDetectionState(deviceId);
|
||||
}
|
||||
// 更新缓存
|
||||
lastDetectedOrderCache.put(deviceId, orderId);
|
||||
|
||||
log.debug("[BeaconDetection] 从工单状态获取区域:deviceId={}, areaId={}, orderId={}",
|
||||
deviceId, areaId, currentOrder.getOrderId());
|
||||
deviceId, areaId, orderId);
|
||||
|
||||
// 3. 获取该区域的信标配置(从 BEACON 类型的设备获取)
|
||||
CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper beaconConfigWrapper = configService
|
||||
@@ -331,4 +353,26 @@ public class BeaconDetectionRuleProcessor {
|
||||
BadgeDeviceStatusRedisDAO.OrderInfo currentOrder = badgeDeviceStatusRedisDAO.getCurrentOrder(deviceId);
|
||||
return currentOrder != null && !currentOrder.getAreaId().equals(areaId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理设备所有区域的检测状态
|
||||
* <p>
|
||||
* 用于工单切换场景,清理本地缓存。
|
||||
* Redis 数据(arrivedTime、signalLoss、rssiWindow)由以下路径清理:
|
||||
* <ul>
|
||||
* <li>工单完成时:SignalLossRuleProcessor.cleanupRedisData()</li>
|
||||
* <li>自然过期:Redis TTL 自动清理</li>
|
||||
* <li>新数据覆盖:每次检测都会更新滑动窗口</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
*/
|
||||
private void cleanupAllDetectionState(Long deviceId) {
|
||||
if (deviceId == null) {
|
||||
return;
|
||||
}
|
||||
// 清理本地缓存
|
||||
lastDetectedOrderCache.remove(deviceId);
|
||||
log.info("[BeaconDetection] 已清理设备工单切换检测状态: deviceId={}", deviceId);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user