fix(feishu): invoke SDK disconnect() directly and surface cleanup failures

This commit is contained in:
matevip 2026-05-25 21:31:09 +08:00
parent 54e3f7f3fa
commit e9ead959b8

View File

@ -548,15 +548,20 @@ public class FeishuChannelAdapter extends AbstractChannelAdapter implements Stre
} }
/** /**
* 关闭 WebSocket 连接 * 关闭 WebSocket 连接
* <p> * <p>
* 必须主动关闭底层 WebSocket 连接并触发 SDK 的内部清理停止 pingLoop * 必须主动关闭底层 WebSocket 连接并触发 SDK 的内部清理停止 pingLoop
* 释放 ExecutorService仅置空引用会导致旧连接的 pingLoop 和线程池 * 释放 ExecutorService仅置空引用会导致旧连接的 pingLoop 和线程池
* 持续运行造成文件描述符和线程泄漏最终使新连接无法建立 * 持续运行造成文件描述符和线程泄漏最终使新连接无法建立
* <p> * <p>
* SDK {@code disconnect()} protected 无法直接调用通过反射 * SDK 内部 {@code disconnect()} 这条单一入口完成 cleanup 它本身就是
* 获取内部 {@code conn} 字段并发送 close(1000) 触发 SDK * SDK {@code onClosed} 回调里调用的方法包含
* {@code onClosed disconnect()} 清理链路 * {@code conn.close(1000) executor.shutdown() 字段清零} 的全套动作
* 该方法在 SDK 2.6.1 中是 {@code protected}外部需通过反射 + setAccessible
* 调用SDK 2.7.1 起新增了 public {@code close()}届时整段反射可以删除
* <p>
* 反射失败例如未来 SDK 重命名 {@code disconnect} WARN 级别记录而非
* 静默吞掉避免泄漏在升级后悄无声息地复发
*/ */
private void stopWebSocket() { private void stopWebSocket() {
cancelSilentDisconnectWatchdog(); cancelSilentDisconnectWatchdog();
@ -567,17 +572,14 @@ public class FeishuChannelAdapter extends AbstractChannelAdapter implements Stre
} }
if (wsClient != null) { if (wsClient != null) {
try { try {
// 反射获取 protected conn 字段发送 close(1000) 触发 SDK 清理 var disconnect = wsClient.getClass().getDeclaredMethod("disconnect");
var connField = wsClient.getClass().getDeclaredField("conn"); disconnect.setAccessible(true);
connField.setAccessible(true); disconnect.invoke(wsClient);
Object conn = connField.get(wsClient); } catch (NoSuchMethodException e) {
if (conn != null) { log.warn("[feishu] SDK Client.disconnect() not found — WebSocket cleanup skipped, "
// conn OkHttp WebSocketclose(1000) 会触发 onClosed disconnect() + "leak may recur until SDK API is re-verified: {}", e.getMessage());
var closeMethod = conn.getClass().getMethod("close", int.class, String.class);
closeMethod.invoke(conn, 1000, "client closed");
}
} catch (Exception e) { } catch (Exception e) {
log.debug("[feishu] Error during WebSocket disconnect: {}", e.getMessage()); log.warn("[feishu] WebSocket disconnect failed: {}", e.getMessage());
} }
} }
wsClient = null; wsClient = null;