fix(agent): map closed database worker to 503

This commit is contained in:
InfinityPacer
2026-08-23 11:44:18 +08:00
parent e0f70fa920
commit cc8e4bc510
3 changed files with 39 additions and 6 deletions
-2
View File
@@ -5,7 +5,6 @@
""" """
from app.api.dependencies.agent import ( from app.api.dependencies.agent import (
get_agent_chat_persistence,
get_agent_chat_service, get_agent_chat_service,
get_message_query_service, get_message_query_service,
) )
@@ -53,7 +52,6 @@ from app.api.dependencies.workflow import (
# 兼容聚合入口只显式列出既有 FastAPI 依赖,不向插件制造新的动态导出规则。 # 兼容聚合入口只显式列出既有 FastAPI 依赖,不向插件制造新的动态导出规则。
__all__ = [ __all__ = [
"get_agent_chat_persistence",
"get_agent_chat_service", "get_agent_chat_service",
"get_auth_service", "get_auth_service",
"get_current_active_manage_user", "get_current_active_manage_user",
+10 -3
View File
@@ -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.plugin.routes import FastAPIDynamicRouteRegistry
from app.adapters.web.health import install_health_routes from app.adapters.web.health import install_health_routes
from app.application.plugin.routes import configure_plugin_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 ( from app.adapters.web.security.access import (
configure_token_codec, configure_token_codec,
verify_apikey, verify_apikey,
@@ -234,9 +237,9 @@ async def localized_http_exception_handler(
async def database_worker_overloaded_handler( async def database_worker_overloaded_handler(
request: Request, request: Request,
_exc: DatabaseWorkerOverloadedError, _exc: DatabaseWorkerClosedError | DatabaseWorkerOverloadedError,
) -> JSONResponse: ) -> JSONResponse:
"""将数据库短事务背压映射为可重试的 503 响应。""" """将数据库 worker 暂不可用映射为可重试的 503 响应。"""
return await localized_http_exception_handler( return await localized_http_exception_handler(
request, request,
HTTPException( HTTPException(
@@ -335,6 +338,10 @@ def create_app() -> FastAPI:
DatabaseWorkerOverloadedError, DatabaseWorkerOverloadedError,
database_worker_overloaded_handler, database_worker_overloaded_handler,
) )
_app.add_exception_handler(
DatabaseWorkerClosedError,
database_worker_overloaded_handler,
)
_app.add_exception_handler( _app.add_exception_handler(
RequestValidationError, RequestValidationError,
localized_validation_exception_handler, localized_validation_exception_handler,
+29 -1
View File
@@ -23,7 +23,10 @@ from app.factory import (
localized_unhandled_exception_handler, localized_unhandled_exception_handler,
localized_validation_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.localization import LocaleHelper
from app.runtime.config import settings from app.runtime.config import settings
from app.schemas.common import JsonData from app.schemas.common import JsonData
@@ -67,6 +70,10 @@ def api_app() -> FastAPI:
DatabaseWorkerOverloadedError, DatabaseWorkerOverloadedError,
database_worker_overloaded_handler, database_worker_overloaded_handler,
) )
app.add_exception_handler(
DatabaseWorkerClosedError,
database_worker_overloaded_handler,
)
from fastapi.exceptions import RequestValidationError from fastapi.exceptions import RequestValidationError
app.add_exception_handler( app.add_exception_handler(
@@ -125,6 +132,11 @@ def api_app() -> FastAPI:
"""模拟数据库短事务容量耗尽。""" """模拟数据库短事务容量耗尽。"""
raise DatabaseWorkerOverloadedError("worker full") 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) @app.get("/native", response_model=None)
async def get_native_response() -> dict[str, bool]: async def get_native_response() -> dict[str, bool]:
"""返回显式旁路的原生 JSON 协议。""" """返回显式旁路的原生 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( @pytest.mark.parametrize(
"path", "path",
[ [