From 7eaecbad5a0913ed04ca3bc10c930bb051dd2bd9 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sat, 9 May 2026 02:38:08 +0900 Subject: [PATCH] refac --- backend/open_webui/__init__.py | 7 +++++++ backend/open_webui/internal/db.py | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/backend/open_webui/__init__.py b/backend/open_webui/__init__.py index be25227d36..92cadefe7c 100644 --- a/backend/open_webui/__init__.py +++ b/backend/open_webui/__init__.py @@ -1,6 +1,7 @@ import base64 import os import random +import sys from pathlib import Path from typing import Annotated @@ -68,12 +69,18 @@ def serve( import open_webui.main # noqa: F401 from open_webui.env import UVICORN_WORKERS # Import the workers setting + # On Windows, uvicorn's default loop factory hardcodes ProactorEventLoop, + # which is incompatible with psycopg v3 async. Setting loop='none' lets + # asyncio.run() respect the WindowsSelectorEventLoopPolicy set in db.py. + loop = 'none' if sys.platform == 'win32' else 'auto' + uvicorn.run( 'open_webui.main:app', host=host, port=port, forwarded_allow_ips='*', workers=UVICORN_WORKERS, + loop=loop, ) diff --git a/backend/open_webui/internal/db.py b/backend/open_webui/internal/db.py index c9e4f318e1..1bb9db5bb4 100644 --- a/backend/open_webui/internal/db.py +++ b/backend/open_webui/internal/db.py @@ -1,4 +1,5 @@ import os +import sys import json import logging from contextlib import asynccontextmanager, contextmanager @@ -332,6 +333,14 @@ get_db = contextmanager(get_session) # all work without any stripping or translation. ASYNC_SQLALCHEMY_DATABASE_URL = _make_async_url(SQLALCHEMY_DATABASE_URL) +# psycopg v3 cannot run in async mode under Windows' default +# ProactorEventLoop — switch to SelectorEventLoop before creating +# the async engine. This runs at import time, which is early enough +# to cover every entry point (workers, reload, direct invocations). +if sys.platform == 'win32' and _is_postgres_url(DATABASE_URL): + import asyncio + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + if 'sqlite' in ASYNC_SQLALCHEMY_DATABASE_URL: # Generous default — async coroutines + no session sharing = high connection demand. _sqlite_pool_size = DATABASE_POOL_SIZE if isinstance(DATABASE_POOL_SIZE, int) and DATABASE_POOL_SIZE > 0 else 512