Asyncio תחת WSGI: הרצת קורוטינות בבטחה
רקע קצר
ב-WebApp שמורץ תחת WSGI (Flask + Gunicorn/gevent), עלולה להיות לולאת Event
פעילה כבר בתוך ה-thread של הבקשה. במצב כזה קריאה ל-asyncio.run תזרוק
חריגה ותפיל את הבקשה, ולעתים תשאיר קורוטינה ”תלויה“ ללא await.
תסמינים נפוצים
RuntimeError: asyncio.run() cannot be called from a running event loopRuntimeError: This event loop is already runningRuntimeWarning: coroutine was never awaited
מתי זה קורה בפועל
בדיקות בריאות DB שמריצות קורוטינות מתוך בקשת WSGI.
כל עטיפה שמריצה קורוטינה ב-thread ”נקי“ אבל מתנגש עם gevent.
מצב מרוץ שבו ה-loop משתנה בין בדיקה להרצה.
דפוס בטוח מומלץ
נסה לקבל loop קיים ב-thread הנוכחי.
אם אין loop, צור חדש והגדר אותו ל-thread.
הרץ עם
run_until_complete.אם מתקבלת שגיאת ”event loop is already running“, בצע fallback להרצה ב-threadpool.
דוגמה קצרה
async def _runner():
return await awaitable
def _run_in_thread():
try:
loop = asyncio.get_event_loop()
except RuntimeError:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
return loop.run_until_complete(_runner())
except RuntimeError as e:
err = str(e).lower()
if "event loop is already running" in err:
return threadpool.submit(_run_in_thread).result()
raise
Checklist לפני דיפלוי
אין שימוש ישיר ב-
asyncio.runבתוך WSGI thread.קיימת שכבת fallback ל-threadpool במקרה של loop פעיל.
הודעות השגיאה מכסות גם
asyncio.run() cannot be called...וגםevent loop is already running.