在DigitalOcean应用平台上将FastAPI挂载到Flask的问题
我有一个Flask应用,并把一个FastAPI应用挂在它上面,因此Flask的根路径在 /,API的路径在 /api/v1。本地我在Windows机器上用Waitress运行,效果很好。我把它部署到Digital Ocean App Platform,它使用Gunicorn,API工作正常,一些Flask路由(不使用API的简单路由)也同样工作良好。问题在于,当我尝试一个使用API的 Flask路由时,在日志中我看到我的路由被调用,而调用API的那一行(使用requests)会报错,我相当确定这是一个超时错误(大约30秒后才失败)。然后在日志里我看到工作进程退出、重新启动,然后我看到来自API调用的GET请求,最终返回200成功。看起来就像Flask应用在等待API的响应,但API无法响应,因为Flask应用忙于等待API。一旦Flask应用放弃等待,排队中的API调用就会执行。再次强调,这个问题在本地不存在,只有部署到DO时才会出现。下面是日志,以防有用:
Mar 03 04:49:31 [2026-03-03 04:49:31 +0000] [15] [INFO] Booting worker with pid: 15
Mar 03 04:49:31 [2026-03-03 04:49:31 +0000] [1] [INFO] Control socket listening at /workspace/gunicorn.ctl
Mar 03 04:55:50 [2026-03-03 04:55:50 +0000] [1] [CRITICAL] WORKER TIMEOUT (pid:15)
Mar 03 04:55:50 [2026-03-03 04:55:50 +0000] [15] [ERROR] Error handling request /person/viewpersons
Mar 03 04:55:50 Traceback (most recent call last):
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/site-packages/gunicorn/workers/sync.py", line 142, in handle
Mar 03 04:55:50 self.handle_request(listener, req, client, addr)
Mar 03 04:55:50 ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/site-packages/gunicorn/workers/sync.py", line 185, in handle_request
Mar 03 04:55:50 respiter = self.wsgi(environ, resp.start_response)
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/site-packages/flask/app.py", line 1536, in __call__
Mar 03 04:55:50 return self.wsgi_app(environ, start_response)
Mar 03 04:55:50 ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/site-packages/werkzeug/middleware/dispatcher.py", line 81, in __call__
Mar 03 04:55:50 return app(environ, start_response)
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/site-packages/flask/app.py", line 1511, in wsgi_app
Mar 03 04:55:50 response = self.full_dispatch_request()
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/site-packages/flask/app.py", line 917, in full_dispatch_request
Mar 03 04:55:50 rv = self.dispatch_request()
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/site-packages/flask/app.py", line 902, in dispatch_request
Mar 03 04:55:50 return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
Mar 03 04:55:50 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
Mar 03 04:55:50 File "/workspace/contactwerx/app/routers/person.py", line 149, in viewpersons
Mar 03 04:55:50 res = requests.get(Config.API_BASE_URL+"relationship/type/")
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/site-packages/requests/api.py", line 73, in get
Mar 03 04:55:50 return request("get", url, params=params, **kwargs)
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/site-packages/requests/api.py", line 59, in request
Mar 03 04:55:50 return session.request(method=method, url=url, **kwargs)
Mar 03 04:55:50 ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/site-packages/requests/sessions.py", line 589, in request
Mar 03 04:55:50 resp = self.send(prep, **send_kwargs)
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/site-packages/requests/sessions.py", line 703, in send
Mar 03 04:55:50 r = adapter.send(request, **kwargs)
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/site-packages/requests/adapters.py", line 644, in send
Mar 03 04:55:50 resp = conn.urlopen(
Mar 03 04:55:50 method=request.method,
Mar 03 04:55:50 ...<9 lines>...
Mar 03 04:55:50 chunked=chunked,
Mar 03 04:55:50 )
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/site-packages/urllib3/connectionpool.py", line 787, in urlopen
Mar 03 04:55:50 response = self._make_request(
Mar 03 04:55:50 conn,
Mar 03 04:55:50 ...<10 lines>...
Mar 03 04:55:50 **response_kw,
Mar 03 04:55:50 )
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/site-packages/urllib3/connectionpool.py", line 534, in _make_request
Mar 03 04:55:50 response = conn.getresponse()
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/site-packages/urllib3/connection.py", line 571, in getresponse
Mar 03 04:55:50 httplib_response = super().getresponse()
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/http/client.py", line 1430, in getresponse
Mar 03 04:55:50 response.begin()
Mar 03 04:55:50 ~~~~~~~~~~~~~~^^
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/http/client.py", line 331, in begin
Mar 03 04:55:50 version, status, reason = self._read_status()
Mar 03 04:55:50 ~~~~~~~~~~~~~~~~~^^
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/http/client.py", line 292, in _read_status
Mar 03 04:55:50 line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
Mar 03 04:55:50 ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/socket.py", line 719, in readinto
Mar 03 04:55:50 return self._sock.recv_into(b)
Mar 03 04:55:50 ~~~~~~~~~~~~~~~~~~~~^^^
Mar 03 04:55:50 File "/workspace/.heroku/python/lib/python3.13/site-packages/gunicorn/workers/base.py", line 198, in handle_abort
Mar 03 04:55:50 sys.exit(1)
Mar 03 04:55:50 ~~~~~~~~^^^
Mar 03 04:55:50 SystemExit: 1
Mar 03 04:55:50 10.244.147.226 - - [03/Mar/2026:04:55:50 +0000] "GET /person/viewpersons HTTP/1.1" 500 0 "-" "-"
Mar 03 04:55:50 [2026-03-03 04:55:50 +0000] [15] [INFO] Worker exiting (pid: 15)
Mar 03 04:55:51 [2026-03-03 04:55:51 +0000] [17] [INFO] Booting worker with pid: 17
Mar 03 04:55:53 169.254.42.1 - - [03/Mar/2026:04:55:53 +0000] "GET /api/v1/relationship/type/ HTTP/1.1" 200 63 "-" "python-requests/2.32.5"
解决方案
问题在于我把FastAPI应用挂在Flask应用之上,而不是相反。因此要改成把Flask挂载到FastAPI上,我在main.py里做了如下操作:
from a2wsgi import WSGIMiddleware
...
fastapiapp.mount("/", WSGIMiddleware(flaskapp))
然后我把 worker_class = "uvicorn.workers.UvicornWorker" 添加到了gunicorn配置文件中。另一种做法意味着gunicorn忙于处理Flask请求(该请求试图发出一个FastAPI请求),因此无法处理FastAPI请求。但这样,uvicorn/fastapi就由它们来处理,显然它们可以处理异步请求。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。