Uvicorn 服务器意外关闭

8
我正在使用FastAPI框架,由Uvicorn服务器提供支持。我的应用程序需要在给定的终端点(/run)上运行一些耗时的数字计算。为此,我使用了FastAPI中的'background_task'(它基本上是Starlette中的'background_task')。
当应用程序运行一段时间后,服务器出于某种原因关闭。
应用程序的日志如下:
INFO: Started server process [922]
INFO: Waiting for application startup.
DEBUG: None - ASGI [1] Started
DEBUG: None - ASGI [1] Sent {'type': 'lifespan.startup'}
DEBUG: None - ASGI [1] Received {'type': 'lifespan.startup.complete'}
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
DEBUG: ('10.0.2.111', 57396) - Connected
DEBUG: ('10.0.2.111', 57397) - Connected
DEBUG: ('10.0.2.111', 57396) - ASGI [2] Started
DEBUG: ('10.0.2.111', 57396) - ASGI [2] Received {'type': 'http.response.start', 'status': 200, 'headers': '<...>'}
INFO: ('10.0.2.111', 57396) - "GET /run HTTP/1.1" 200
DEBUG: ('10.0.2.111', 57396) - ASGI [2] Received {'type': 'http.response.body', 'body': '<32 bytes>'}
DEBUG: ('10.0.2.111', 57396) - ASGI [3] Started
DEBUG: ('10.0.2.111', 57396) - ASGI [3] Received {'type': 'http.response.start', 'status': 404, 'headers': '<...>'}
INFO: ('10.0.2.111', 57396) - "GET /favicon.ico HTTP/1.1" 404
DEBUG: ('10.0.2.111', 57396) - ASGI [3] Received {'type': 'http.response.body', 'body': '<22 bytes>'}
DEBUG: ('10.0.2.111', 57396) - ASGI [3] Completed

...

DEBUG: ('10.0.2.111', 57396) - Disconnected
... The background task is completed.
DEBUG: ('10.0.2.111', 57396) - ASGI [2] Completed
DEBUG: ('10.0.2.111', 57397) - Disconnected
DEBUG: ('10.0.2.111', 57405) - Connected

...
The application goes on, with requests and completed background tasks.
At some point, during the execution of a background task:

INFO: Shutting down
DEBUG: ('10.0.2.111', 57568) - Disconnected
DEBUG: ('10.0.2.111', 57567) - Disconnected
INFO: Waiting for background tasks to complete. (CTRL+C to force quit)
DEBUG: ('10.0.2.111', 57567) - ASGI [6] Completed
INFO: Waiting for application shutdown.
DEBUG: None - ASGI [1] Sent {'type': 'lifespan.shutdown'}
DEBUG: None - ASGI [1] Received {'type': 'lifespan.shutdown.complete'}
DEBUG: None - ASGI [1] Completed
INFO: Finished server process [922]

我真的不明白为什么会发生这种情况。我不知道该尝试什么来修复它。
我的代码长这样。
#!/usr/bin/env python3.7
import time
from fastapi import FastAPI, BackgroundTasks
import uvicorn
from starlette.responses import JSONResponse
import my_imports_from_project

analysis_api = FastAPI()

@analysis_api.get("/")
def root():
    return {"message": "root"}


@analysis_api.get("/test")
def test():
    return {"message": "test"}

@analysis_api.get("/run")
def run(name: str, background_task: BackgroundTasks):
    try:
        some_checks(name)
    except RaisedExceptions:
        body = {"running": False,
                "name": name,
                "cause": "Not found in database"}
        return JSONResponse(status_code=400, content=body)
    body = {"running": True,
            "name": name}
    background_task.add_task(run_analysis, name)
    return JSONResponse(status_code=200, content=body)


if __name__ == "__main__":
    uvicorn.run("api:analysis_api", host="0.0.0.0", log_level="debug")


你尝试过通过gunicorn运行uvicorn吗?gunicorn可以保持进程运行。 - Will
我在想后台任务的完成是否会以某种方式触发关闭请求。 - Will
关于gunicorn:
  • 发生了完全相同的事情,但至少gunicord重新启动了服务器。
关于触发关闭的任务:
  • 我不知道,它只是进行计算并将结果保存在数据库中。此外,一些任务成功完成,只有一个任务会关闭服务器(所有任务都是相等的)。
- Davide Melli
1个回答

7
这是我解决整个问题的方法。
我认为问题在于我的任务会生成一些进程来执行计算。因此,我现在使用了 multiprocessing.Process() 而不是 FastApi 的 background_task,这样就解决了问题。
从 FastApi 的人们指出,如果项目变得复杂大型,这种解决方案可能无法很好地扩展。在这种情况下,强烈建议使用消息队列 + 任务运行(如在 FastApi 网站上建议的那样)。
然而,对于小型项目,使用 multiprocessing.Processsubprocess.Popen 解决方案完全可以。

1
使用外部队列不仅可以让您控制应用程序实例中处理并行工作的消费者/订阅者/线程数量,还可以让您部署多个应用程序实例,既可以添加到队列,又可以在队列上工作。此外,它还可以在处理正在处理它们的实例崩溃时启用自动重新启动/恢复排队的工作项。 - Danny Varod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接