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 分別執行於不同 thread 的情況,並判斷預期採用以 instance 或 async API 為基礎的方式。完成標準是:彼此獨立的 ws.Client instance 不再共用或覆寫 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 摘要。