diff --git a/app/api/deps.py b/app/api/deps.py index 6073df004..9007667af 100644 --- a/app/api/deps.py +++ b/app/api/deps.py @@ -5,7 +5,6 @@ """ from app.api.dependencies.agent import ( - get_agent_chat_persistence, get_agent_chat_service, get_message_query_service, ) @@ -53,7 +52,6 @@ from app.api.dependencies.workflow import ( # 兼容聚合入口只显式列出既有 FastAPI 依赖,不向插件制造新的动态导出规则。 __all__ = [ - "get_agent_chat_persistence", "get_agent_chat_service", "get_auth_service", "get_current_active_manage_user", diff --git a/app/factory.py b/app/factory.py index 8c947c741..7db6a5e82 100644 --- a/app/factory.py +++ b/app/factory.py @@ -14,7 +14,10 @@ from app.adapters.observability.otel import build_observation_port from app.adapters.web.plugin.routes import FastAPIDynamicRouteRegistry from app.adapters.web.health import install_health_routes from app.application.plugin.routes import configure_plugin_routes -from app.application.database import DatabaseWorkerOverloadedError +from app.application.database import ( + DatabaseWorkerClosedError, + DatabaseWorkerOverloadedError, +) from app.adapters.web.security.access import ( configure_token_codec, verify_apikey, @@ -234,9 +237,9 @@ async def localized_http_exception_handler( async def database_worker_overloaded_handler( request: Request, - _exc: DatabaseWorkerOverloadedError, + _exc: DatabaseWorkerClosedError | DatabaseWorkerOverloadedError, ) -> JSONResponse: - """将数据库短事务背压映射为可重试的 503 响应。""" + """将数据库 worker 暂不可用映射为可重试的 503 响应。""" return await localized_http_exception_handler( request, HTTPException( @@ -335,6 +338,10 @@ def create_app() -> FastAPI: DatabaseWorkerOverloadedError, database_worker_overloaded_handler, ) + _app.add_exception_handler( + DatabaseWorkerClosedError, + database_worker_overloaded_handler, + ) _app.add_exception_handler( RequestValidationError, localized_validation_exception_handler, diff --git a/tests/test_api_response.py b/tests/test_api_response.py index c4419d92e..65cac63c4 100644 --- a/tests/test_api_response.py +++ b/tests/test_api_response.py @@ -23,7 +23,10 @@ from app.factory import ( localized_unhandled_exception_handler, localized_validation_exception_handler, ) -from app.application.database import DatabaseWorkerOverloadedError +from app.application.database import ( + DatabaseWorkerClosedError, + DatabaseWorkerOverloadedError, +) from app.runtime.localization import LocaleHelper from app.runtime.config import settings from app.schemas.common import JsonData @@ -67,6 +70,10 @@ def api_app() -> FastAPI: DatabaseWorkerOverloadedError, database_worker_overloaded_handler, ) + app.add_exception_handler( + DatabaseWorkerClosedError, + database_worker_overloaded_handler, + ) from fastapi.exceptions import RequestValidationError app.add_exception_handler( @@ -125,6 +132,11 @@ def api_app() -> FastAPI: """模拟数据库短事务容量耗尽。""" raise DatabaseWorkerOverloadedError("worker full") + @app.get("/database-closed") + async def get_database_closed() -> None: + """模拟数据库 worker 在关闭态拒绝新任务。""" + raise DatabaseWorkerClosedError("worker closed") + @app.get("/native", response_model=None) async def get_native_response() -> dict[str, bool]: """返回显式旁路的原生 JSON 协议。""" @@ -219,6 +231,22 @@ async def test_database_worker_overload_is_retryable_service_unavailable( } +async def test_database_worker_closed_is_retryable_service_unavailable( + api_app: FastAPI, +): + """数据库 worker 关闭态应返回 503,而不是落入通用 500。""" + async with make_client(api_app) as client: + response = await client.get("/database-closed") + + assert response.status_code == 503 + assert response.headers["retry-after"] == "1" + assert response.json() == { + "success": False, + "message": "服务当前繁忙,请稍后重试", + "data": None, + } + + @pytest.mark.parametrize( "path", [