fix: 修复设备断开后通讯层会话缓存未及时清理的问题

之前设备断开连接时(channelInactive),虽然会关闭会话并通知应用层,
但通讯层的 Caffeine 缓存没有立即清除,导致:
- 下行指令仍能找到"幽灵会话",写入已关闭的 channel 后静默失败
- 应用层无法感知设备已离线,用户体验不佳

改动:
- ProtocolSession 新增 closeCallback 回调机制,close() 时自动通知注册中心
- ProtocolSession 新增 AtomicBoolean closed 状态,防止重复关闭
- DefaultProtocolSessionRegistryProvider.register() 时自动设置回调
- 新增单元测试验证回调机制

现在设备断开后,App 层下发指令时能立即感知到会话不存在,
并在日志中明确提示"充电桩会话不存在"。
This commit is contained in:
三丙
2026-01-29 20:38:48 +08:00
parent fa9524d302
commit b3270c21b0
3 changed files with 215 additions and 2 deletions

View File

@@ -26,6 +26,8 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Function;
/**
@@ -57,6 +59,17 @@ public abstract class ProtocolSession implements Closeable {
@Setter
private Forwarder forwarder;
/**
* 会话关闭回调,用于通知注册中心清除缓存
*/
@Setter
private Consumer<UUID> closeCallback;
/**
* 防止重复关闭
*/
private final AtomicBoolean closed = new AtomicBoolean(false);
protected ProtocolSession(String protocolName) {
this.protocolName = protocolName;
this.pileCodeSet = new LinkedHashSet<>();
@@ -72,12 +85,29 @@ public abstract class ProtocolSession implements Closeable {
}
public void close(SessionCloseReason reason) {
// 防止重复关闭
if (!closed.compareAndSet(false, true)) {
log.debug("[{}] Protocol会话已关闭忽略重复关闭请求", this);
return;
}
log.info("[{}] Protocol会话关闭原因: {}", this, reason);
// 1. 取消所有定时任务
scheduledFutures.values().forEach(scheduledFuture -> scheduledFuture.cancel(true));
scheduledFutures.clear();
// 转发会话关闭事件到后端
// 2. 通知注册中心清除缓存
if (closeCallback != null) {
try {
closeCallback.accept(id);
log.debug("[{}] 会话关闭回调执行成功", this);
} catch (Exception e) {
log.error("[{}] 会话关闭回调执行失败", this, e);
}
}
// 3. 转发会话关闭事件到后端
if (forwarder != null && !pileCodeSet.isEmpty()) {
for (String pileCode : pileCodeSet) {
@@ -106,6 +136,13 @@ public abstract class ProtocolSession implements Closeable {
}
}
}
/**
* 检查会话是否已关闭
*/
public boolean isClosed() {
return closed.get();
}