WindowsSelectorEventLoopPolicy set before uvicorn.run() is ignored in 0.36.0+ (worked in 0.34.2) #2749
-
|
Setting asyncio.WindowsSelectorEventLoopPolicy() before calling Expected Behavior: Actual Behavior: MRE: """
Test with uvicorn 0.34.2 (works):
uv run --script --with "uvicorn[standard]==0.34.2" --with fastapi \\
--with "psycopg[binary]" uvicorn_issue_mre.py
Test with uvicorn 0.37.0 (fails):
uv run --script --with "uvicorn[standard]==0.37.0" --with fastapi \\
--with "psycopg[binary]" uvicorn_issue_mre.py
Note: psycopg will fail on event loop check before attempting DB connection.
"""
import asyncio
import sys
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
import psycopg
from fastapi import FastAPI
# Global connection - will be None but psycopg checks event loop on import/connect
db_conn: psycopg.AsyncConnection[tuple] | None = None
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
"""FastAPI lifespan to manage database connection"""
global db_conn
loop = asyncio.get_running_loop()
loop_type = type(loop).__name__
print(f"Event loop type: {loop_type}") # noqa: T201
# Try to create async connection - psycopg checks event loop type here
# This will fail on ProactorEventLoop before even trying to connect
try:
db_conn = await psycopg.AsyncConnection.connect(
"postgresql://user:pass@localhost/db",
autocommit=True,
connect_timeout=1,
)
print("✓ Database connected successfully") # noqa: T201
except psycopg.InterfaceError as e:
print(f"✗ psycopg InterfaceError (expected): {e}") # noqa: T201
raise
except Exception as e:
# Connection will fail but that's OK - we're testing event loop
print(f"Connection failed (OK for test): {type(e).__name__}") # noqa: T201
yield
if db_conn:
await db_conn.close()
print("✓ Database connection closed") # noqa: T201
def create_app() -> FastAPI:
"""Factory function to create the FastAPI app"""
app = FastAPI(lifespan=lifespan)
@app.get("/")
async def root() -> dict[str, str]:
return {"message": "Hello World"}
return app
if __name__ == "__main__":
import uvicorn
print(f"Python version: {sys.version}") # noqa: T201
print(f"uvicorn version: {uvicorn.__version__}") # noqa: T201
print(f"Platform: {sys.platform}") # noqa: T201
# On Windows, set the event loop policy BEFORE calling uvicorn.run()
# This works in uvicorn 0.34.2 but fails in 0.36.0+
if sys.platform.startswith("win"):
print("Setting WindowsSelectorEventLoopPolicy...") # noqa: T201
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
print("Starting uvicorn...") # noqa: T201
uvicorn.run(
"uvicorn_issue_mre:create_app",
host="127.0.0.1",
port=8000,
factory=True,
) |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 4 replies
-
|
Note: To use |
Beta Was this translation helpful? Give feedback.
-
|
That did not work unfortunately. File "/path/to/project/asgi.py", line 84, in <module>
uvicorn.run(
File "/path/to/project/.venv/Lib/site-packages/uvicorn/main.py", line 580, in run
server.run()
File "/path/to/project/.venv/Lib/site-packages/uvicorn/server.py", line 65, in run
self.config.setup_event_loop()
File "/path/to/project/.venv/Lib/site-packages/uvicorn/config.py", line 476, in setup_event_loop
loop_setup: Callable | None = import_from_string(LOOP_SETUPS[self.loop])
~~~~~~~~~~~^^^^^^^^^^^
KeyError: 'asyncio:SelectorEventLoop'Loop setups seem to only support these 4 options LOOP_SETUPS: dict[LoopSetupType, str | None] = {
"none": None,
"auto": "uvicorn.loops.auto:auto_loop_setup",
"asyncio": "uvicorn.loops.asyncio:asyncio_setup",
"uvloop": "uvicorn.loops.uvloop:uvloop_setup",
} |
Beta Was this translation helpful? Give feedback.
-
|
I suggest also to document it a bit more explicitly in https://uvicorn.dev/concepts/event-loop/#custom-event-loop |
Beta Was this translation helpful? Give feedback.
Note:
asyncio.set_event_loop_policywill be removed in Python 3.16 https://docs.python.org/3/library/asyncio-policy.html .To use
SelectorEventLoopon Windows, my intuition tells me to try--loop asyncio:SelectorEventLoopeven though I haven't tested it.