Docker+FastAPI启动与关闭异常:Ctrl+C触发asyncio取消错误排查
关于Uvicorn+FastAPI关闭时出现
asyncio.exceptions.CancelledError的问题解析 问题背景
我在排查Uvicorn+FastAPI应用无法接收SIGTERM、Docker Compose需10秒后发送SIGKILL终止的问题时,编写了极简示例应用测试,按下Ctrl+C关闭应用时出现asyncio.exceptions.CancelledError异常,想了解该异常原因,是否是代码、Uvicorn或FastAPI存在问题?
相关文件与输出
示例代码
from fastapi import FastAPI app = FastAPI() @app.get("/") async def root(): return {"message": "Hello World"}
Dockerfile
# Use an official Python runtime as the parent image FROM python:3.11-slim # Set the working directory WORKDIR /app # Copy the requirements.txt files to install dependencies COPY requirements.txt /app/ # Install dependencies RUN pip install -r requirements.txt # FastAPI app COPY . /app/ WORKDIR /app/ CMD ["uvicorn", "fastsample:app", "--host", "0.0.0.0", "--port", "8888"]
控制台输出(已翻译异常信息)
docker run -p 8888:8888 uvidemo INFO: Started server process [1] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:8888 (Press CTRL+C to quit) INFO: 172.17.0.1:41148 - "GET / HTTP/1.1" 200 OK INFO: 172.17.0.1:41148 - "GET / HTTP/1.1" 200 OK INFO: 172.17.0.1:41148 - "GET / HTTP/1.1" 200 OK INFO: 172.17.0.1:41148 - "GET / HTTP/1.1" 200 OK INFO: 172.17.0.1:41148 - "GET / HTTP/1.1" 200 OK ^CINFO: Shutting down INFO: Finished server process [1] ERROR: 回溯(最近的调用最后): 文件 "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 686, in lifespan await receive() 文件 "/usr/local/lib/python3.11/site-packages/uvicorn/lifespan/on.py", line 137, in receive return await self.receive_queue.get() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 文件 "/usr/local/lib/python3.11/asyncio/queues.py", line 158, in get await getter asyncio.exceptions.CancelledError
异常原因解析
这个CancelledError是正常的异步任务终止信号,并非代码、Uvicorn或FastAPI的问题,具体原因:
- 按下Ctrl+C时,系统向进程发送SIGINT信号,Uvicorn收到后启动优雅关闭流程,主动取消所有运行中的异步任务(包括框架内部的生命周期管理协程)。
- 异常来自Starlette(FastAPI依赖的底层框架)的
lifespan协程:应用关闭阶段,该协程仍在等待接收生命周期事件,Uvicorn取消了这个等待操作,触发标准的asyncio.CancelledError。 - 该异常是异步编程中任务被取消时的标准行为,Uvicorn本身会处理此异常,部分版本会打印异常信息,但不影响应用正常关闭。
关于SIGTERM接收问题的补充
你最初排查的Docker Compose需10秒发送SIGKILL的问题,与这个CancelledError无关,常见解决方向:
- 确保Uvicorn以PID 1运行:Docker默认仅向PID 1进程发送信号,若进程PID不是1则无法接收SIGTERM。可修改Dockerfile的CMD为
exec形式:CMD ["exec", "uvicorn", "fastsample:app", "--host", "0.0.0.0", "--port", "8888"] - 调整优雅关闭超时:添加
--timeout-graceful-shutdown参数,给应用足够时间处理完现有请求再退出。
内容的提问来源于stack exchange,提问作者vivekv
相关产品推荐
相关产品推荐

