Repository navigation
[bug] 飞书通道 WebSocket 反复崩溃重连,双向收不到消息(事件循环冲突) #2122
Description
【Bug】飞书通道 WebSocket 反复崩溃重连,双向收不到消息(事件循环冲突)
环境
- Octop 版本:v1.0.2b8(GitHub 最新 release)
- 系统:Windows
- 通道:飞书(FeishuChannel,走 lark_oapi WebSocket 长连接)
现象
- 飞书通道"连接测试"通过(凭证/机器人配置正确,open_id 能解析,WS 首次能 connected 到 wss://msg-frontier.feishu.cn)
- 但每次连上后几秒内即崩溃,自动重连,循环往复,双向均无法收发消息(机器人发不出消息给用户,用户在飞书发给它也不回)
关键报错(octop.log)
- RuntimeError: This event loop is already running(FeishuChannel 守护线程内 lark_oapi Client.start() 调 loop.run_until_complete 时)
- RuntimeError: Task ... got Future ... attached to a different loop(_receive_message_loop / _ping_loop 的 create_task 挂错 loop)
- 后续:ping failed, err: Event loop is closed / receive message loop exit / Feishu WebSocket thread orphaned / 反复 reconnecting
代码定位
- Octop 侧:octop_gateway/channels/feishu.py 的 _run_ws_thread()(约 268-292 行)
在守护线程内 new_event_loop + set_event_loop,并尝试 ws_client_module.loop = loop 改写 lark_oapi.ws.client 的模块级 loop,再调 self._ws_client.start() - 飞书 SDK 侧:lark_oapi/ws/client.py 顶层
try: loop = asyncio.get_event_loop()
except RuntimeError: loop = asyncio.new_event_loop(); asyncio.set_event_loop(loop)
Client.start() 内部所有 run_until_complete / create_task 均引用该模块级全局 loop;若 lark_oapi.ws.client 曾在主线程(Octop 主框架本身是 async 环境)被 import 过,该全局 loop 很可能就是主线程正在运行的 loop,子线程再 run_until_complete 即冲突
预期
FeishuChannel 能稳定保持 WebSocket 长连接,双向正常收发消息
请修复
核心矛盾:lark_oapi SDK 假设"单线程单 loop",Octop 把它放进守护线程并与主 async 框架共存。建议方向(供参考,最终方案你们定):
- 让 lark_oapi.ws.client 的 Client 支持注入独立 event loop / 或在 start() 内基于线程本地(threading.local)持有 loop,而非模块级全局变量
- 或 Octop 侧不再"改写模块全局 loop",改为确保子线程内 import/构造 Client 时其模块级 loop 就是该线程新建的 loop(比如子线程内重新 import lark_oapi.ws.client,避免复用主线程已初始化的模块状态)
- 修复后请补充"主 async 框架 + 守护线程跑 WS 客户端"场景的回归测试,防止再次回归
附:完整日志片段
2026-10-16 20:03:31,669 INFO octop_gateway.channels.feishu — Feishu WebSocket client connecting (daemon thread, session=76dd1721-...)
2026-10-16 20:03:32,073 INFO Lark — connected to wss://msg-frontier.feishu.cn/ws/v2?...
2026-10-16 20:03:32,073 ERROR octop_gateway.channels.feishu — Feishu WebSocket thread failed
Traceback (most recent call last):
...
loop.run_until_complete(_select())
...
RuntimeError: This event loop is already running
2026-10-16 20:03:32,134 WARNING Lark — ping failed, err: Event loop is closed
2026-10-16 20:03:32,134 ERROR Lark — receive message loop exit, err: Task <...> got Future attached to a different loop
2026-10-16 20:03:42,006 ERROR octop_gateway.channels.feishu — Feishu WebSocket thread orphaned; connection slot may remain until it exits
(后续 20:12 起反复 reconnect → connected → exit,死循环)
Activity
fix(feishu): build the lark-oapi client on the WebSocket thread