Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

ws.Client: module-level loop variable prevents multiple instances (multi-bot race condition)

未关闭
#119 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
5/5
预计耗时
一周以上
新手友好度
42/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
停滞
技术栈
python
领域
api

调研方向

从 lark_oapi/ws/client.py 第 26-29 行附近的模块级循环开始,然后跟踪第 171 行的 Client.start() 和 _receive_message_loop。复现 issue 中描述的多个 bot 分别运行在线程中的情况,并确定预期采用基于实例还是 async API 的方案。完成标准是:彼此独立的 ws.Client 实例不再共享或覆盖 event loop,并且可以并发运行而不会出现报告中的 RuntimeError。

由索引模型根据 Issue 内容生成。

描述

Problem

lark_oapi/ws/client.py uses a module-level loop variable (line 26-29):

try:
    loop = asyncio.get_event_loop()
except RuntimeError:
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)

All ws.Client instances share this single loop reference. When multiple Feishu bots are started in separate threads (a common pattern for multi-bot applications), they overwrite each other's loop, causing RuntimeError: This event loop is already running.

Race condition
  1. Thread A: ws_mod.loop = loop_A
  2. Thread B: ws_mod.loop = loop_B (overwrites A)
  3. Thread A: cli.start() → reads ws_mod.loop → gets loop_B → loop_B.run_until_complete()
  4. Thread B: cli.start() → reads ws_mod.loop → gets loop_B → ERROR: already running

Even after connecting, _receive_message_loop (line 171) uses loop.create_task() which may reference the wrong loop.

Current workaround

We replaced ws_mod.loop with a thread-local proxy:

class _ThreadLocalLoopProxy:
    def __getattr__(self, name):
        return getattr(asyncio.get_event_loop(), name)

ws_mod.loop = _ThreadLocalLoopProxy()

This works but is fragile against SDK changes.

Suggested fix

Make ws.Client instance-based, like the Node.js SDK (@larksuiteoapi/node-sdk) already does with WSClient:

class Client:
    def __init__(self, ...):
        self._loop = asyncio.new_event_loop()
        ...

    def start(self):
        self._loop.run_until_complete(self._connect())
        self._loop.create_task(self._ping_loop())
        self._loop.run_until_complete(_select())

Or provide an async start_async() method (as suggested in #96) so the client can integrate with existing event loops (e.g., uvicorn, FastAPI).

Related issues

  • #96 — loop conflicts with async frameworks
  • #109 — concerns about production readiness

Environment

  • lark_oapi version: latest (PyPI)
  • Python: 3.13
  • Use case: multi-bot IM middleware (each bot = separate ws.Client instance in its own thread)
主要语言
Python
星标
560
派生
102
PR 合并指标
30 天内没有已合并 PR

环境准备

这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

larksuite/oapi-sdk-python 的其他 Issue

查看 larksuite/oapi-sdk-python 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。