mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
fix(feishu): properly close WebSocket connection to prevent resource leak (#221)
stopWebSocket() only nullified the wsClient reference without calling disconnect() on the SDK client. This left the old WebSocket connection's pingLoop thread and ExecutorService running, leaking file descriptors and threads on each reconnect. Over time, accumulated leaks prevented new connections from being established, causing the Feishu channel to silently stop receiving messages. Fix: use reflection to access the SDK's protected `conn` field and call close(1000) on the OkHttp WebSocket, triggering the SDK's onClosed → disconnect() cleanup chain. Note: oapi-sdk 2.7.1 adds a public close() method that would make this reflection unnecessary. Consider upgrading as a follow-up. Closes #220
This commit is contained in:
parent
a01f0354eb
commit
54e3f7f3fa
@ -549,7 +549,14 @@ public class FeishuChannelAdapter extends AbstractChannelAdapter implements Stre
|
||||
|
||||
/**
|
||||
* 关闭 WebSocket 连接
|
||||
* SDK 的 start() 在线程中阻塞运行,通过中断线程来触发停止
|
||||
* <p>
|
||||
* 必须主动关闭底层 WebSocket 连接并触发 SDK 的内部清理(停止 pingLoop、
|
||||
* 释放 ExecutorService)。仅置空引用会导致旧连接的 pingLoop 和线程池
|
||||
* 持续运行,造成文件描述符和线程泄漏,最终使新连接无法建立。
|
||||
* <p>
|
||||
* SDK 的 {@code disconnect()} 是 protected 的,无法直接调用。通过反射
|
||||
* 获取内部 {@code conn} 字段并发送 close(1000) 触发 SDK 的
|
||||
* {@code onClosed → disconnect()} 清理链路。
|
||||
*/
|
||||
private void stopWebSocket() {
|
||||
cancelSilentDisconnectWatchdog();
|
||||
@ -558,6 +565,21 @@ public class FeishuChannelAdapter extends AbstractChannelAdapter implements Stre
|
||||
wsThread.interrupt();
|
||||
wsThread = null;
|
||||
}
|
||||
if (wsClient != null) {
|
||||
try {
|
||||
// 反射获取 protected conn 字段,发送 close(1000) 触发 SDK 清理
|
||||
var connField = wsClient.getClass().getDeclaredField("conn");
|
||||
connField.setAccessible(true);
|
||||
Object conn = connField.get(wsClient);
|
||||
if (conn != null) {
|
||||
// conn 是 OkHttp WebSocket,close(1000) 会触发 onClosed → disconnect()
|
||||
var closeMethod = conn.getClass().getMethod("close", int.class, String.class);
|
||||
closeMethod.invoke(conn, 1000, "client closed");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug("[feishu] Error during WebSocket disconnect: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
wsClient = null;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user