在Gunicorn运行的FastAPI端点中使用Django ORM时偶发崩溃的排查求助
在Gunicorn运行的FastAPI端点中使用Django ORM时偶发崩溃的排查求助
大家好,我遇到了一个非常棘手的偶发问题,想请教一下有没有人遇到过类似情况或者有排查思路:
我现在是在异步FastAPI端点中脱离Django应用单独使用Django ORM,服务用Gunicorn来运行。大部分时候所有功能都正常,但偶尔会出现诡异的状况:某个worker进程会突然变成“僵尸进程”,完全无法处理任何请求,原因是数据库连接断开了。
之前我看到相关问题里提到,可以用django.db的close_old_connections方法,或者遍历Django的所有连接,对每个连接调用close_if_unusable_or_obsolete方法。我自己写了一个FastAPI中间件来做这件事,但问题还是没有解决,代码如下:
class OptOutOfRandomConnectionCrashFastapiMiddleware(BaseHTTPMiddleware): def __init__(self, app: ASGIApp, *args, **kwargs) -> None: super().__init__(app) async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response: # Pre-processing response = await call_next(request) app = request.app if not hasattr(app.state, "last_pruned"): app.state.last_pruned = 0 if app.state.last_pruned + 5 < time.time(): start = time.time() app.state.last_pruned = start for conn in connections.all(): conn.close_if_unusable_or_obsolete() print(f"Pruned all connections. Took {round((time.time() - start) * 1000, 1)} miliseconds") # Post-processing return response
补充一下我的环境和配置细节:
- 数据库用的是PostgreSQL,数据库端没有设置短超时参数
- 数据库连接配置我已经开启了每次请求的健康检查,本以为这样能避免“失效连接”的问题:
DATABASES = { "default": dj_database_url.config( default="postgres://postgres:pass@localhost:5432/db_name", conn_max_age=300, conn_health_checks=True, ) }
但偶尔还是会出现worker崩溃的情况,我附上了当时的堆栈跟踪,但完全看不懂这些错误信息到底在说什么:
Traceback (most recent call last): File "/home/ubuntu/py_venv/lib/python3.12/site-packages/uvicorn/protocols/http/h11_impl.py", line 403, in run_asgi result = await app( # type: ignore[func-returns-value] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/ubuntu/py_venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in __call__ return await self.app(scope, receive, send) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/ubuntu/py_venv/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__ await super().__call__(scope, receive, send) File "/home/ubuntu/py_venv/lib/python3.12/site-packages/starlette/applications.py", line 113, in __call__ await self.middleware_stack(scope, receive, send) File "/home/ubuntu/py_venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 187, in __c all__ raise exc File "/home/ubuntu/py_venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 165, in __c all__ await self.app(scope, receive, _send) File "/home/ubuntu/py_venv/lib/python3.12/site-packages/starlette/middleware/cors.py", line 85, in __call __ await self.app(scope, receive, send) File "/home/ubuntu/py_venv/lib/python3.12/site-packages/honeybadger/contrib/asgi.py", line 109, in _run_a sgi3 File "/home/ubuntu/py_venv/lib/python3.12/site-packages/honeybadger/contrib/asgi.py", line 118, in _run_a pp raise exc from None File "/home/ubuntu/py_venv/lib/python3.12/site-packages/honeybadger/contrib/asgi.py", line 115, in _run_a pp return await callback() ^^^^^^^^^^^^^^^^ File "/home/ubuntu/py_venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in __call__ await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) File "/home/ubuntu/py_venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wra pped_app raise exc File "/home/ubuntu/py_venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wra pped_app await app(scope, receive, sender) File "/home/ubuntu/py_venv/lib/python3.12/site-packages/starlette/routing.py", line 715, in __call__ await self.middleware_stack(scope, receive, send) File "/home/ubuntu/py_venv/lib/python3.12/site-packages/starlette/routing.py", line 735, in app await route.handle(scope, receive, send) File "/home/ubuntu/py_venv/lib/python3.12/site-packages/starlette/routing.py", line 288, in handle await self.app(scope, receive, send) File "/home/ubuntu/py_venv/lib/python3.12/site-packages/starlette/routing.py", line 76, in app await wrap_app_handling_exceptions(app, request)(scope, receive, send) File "/home/ubuntu/py_venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wra pped_app raise exc File "/home/ubuntu/py_venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wra pped_app await app(scope, receive, sender) File "/home/ubuntu/py_venv/lib/python3.12/site-packages/starlette/routing.py", line 73, in app response = await f(request) ^^^^^^^^^^^^^^^^ File "/home/ubuntu/py_venv/lib/python3.12/site-packages/fastapi/routing.py", line 301, in app raw_response = await run_endpoint_function( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/ubuntu/py_venv/lib/python3.12/site-packages/fastapi/routing.py", line 212, in run_endpoint_fu nction return await dependant.call(**values) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/ubuntu/stateshift/main.py", line 181, in email_exists user = await User.objects.filter(email=email).afirst() ^^^^^^^^^^^^^^^^ File "/home/ubuntu/py_venv/lib/python3.12/site-packages/fastapi/routing.py", line 301, in app raw_response = await run_endpoint_function( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/ubuntu/py_venv/lib/python3.12/site-packages/fastapi/routing.py", line 212, in run_endpoint_function return await dependant.call(**values) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/ubuntu/stateshift/main.py", line 181, in email_exists user = await User.objects.filter(email=email).afirst()
这个问题已经严重影响了服务的稳定性,因为不知道什么时候就会有worker挂掉。有没有人能给我一些排查的方向或者解决思路?
备注:内容来源于stack exchange,提问作者George
相关产品推荐
相关产品推荐

