ws.Client: module-level loop variable prevents multiple instances (multi-bot race condition)
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Idoneità per principianti
- 42/100
Direzione di ricerca
Inizia in lark_oapi/ws/client.py, intorno al loop a livello di modulo alle righe 26-29, quindi segui Client.start() e _receive_message_loop alla riga 171. Riproduci il caso con più bot in thread separati descritto nell’issue e determina l’approccio previsto basato sulle istanze o sull’async API. Il lavoro è completato quando le istanze indipendenti di ws.Client non condividono né sovrascrivono più un event loop e possono essere eseguite contemporaneamente senza il RuntimeError segnalato.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
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
- Thread A:
ws_mod.loop = loop_A - Thread B:
ws_mod.loop = loop_B(overwrites A) - Thread A:
cli.start()→ readsws_mod.loop→ getsloop_B→loop_B.run_until_complete() - Thread B:
cli.start()→ readsws_mod.loop→ getsloop_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 —
loopconflicts 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.Clientinstance in its own thread)
- Lingua principale
- Python
- Stelle
- 560
- Fork
- 102
- Metriche di merge delle PR
- Nessuna PR unita negli ultimi 30g
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di larksuite/oapi-sdk-python
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 67/100
larksuite/oapi-sdk-python#163 · 1 commento ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
larksuite/oapi-sdk-python#162 · 1 commento ·
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 94/100
larksuite/oapi-sdk-python#161 ·
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 90/100
larksuite/oapi-sdk-python#160 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
larksuite/oapi-sdk-python#159 ·
Tutte le issue di larksuite/oapi-sdk-python
Issue simili
-
Claiming namespace `apoint`Apertanamespace operations
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 82/100
EclipseFdn/open-vsx.org#13573 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
collective/icalendar#1854 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
rancher/rancher-ai-agent#412 ·
I maintainer di solito rispondono entro 6 giorni
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
TUDelftGeodesy/DePSI#134 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
HenriquesLab/rxiv-maker#335 ·