FastAPI中如何在服务关闭时终止无限循环?
FastAPI服务关闭时终止路由中的无限循环
根路由/包含一个无限循环(实际场景为WebSocket长连接),按下CTRL+C停止服务时,shutdown事件无法触发,服务永久挂起。原代码中全局变量running始终为True,导致循环无法终止。
问题原因
Uvicorn在收到终止信号后,会先等待所有活跃的请求任务执行完成,才会触发FastAPI的shutdown事件。而路由中的无限循环任务一直未结束,导致shutdown事件永远无法执行,形成死锁。
解决方案
方案1:监听请求任务的取消事件(推荐)
异步任务在服务关闭时会收到asyncio.CancelledError,捕获该异常即可终止循环,这是异步场景下的标准处理方式:
from fastapi import FastAPI import asyncio app = FastAPI() @app.get("/") async def index(): try: while True: await asyncio.sleep(0.1) # 实际场景中可替换为WebSocket消息处理逻辑 except asyncio.CancelledError: # 执行清理操作,比如关闭WebSocket连接、释放资源 print("请求任务被取消,终止循环") raise # 必须重新抛出异常,让FastAPI完成正常收尾
方案2:注册信号处理器直接修改状态
通过监听系统终止信号(SIGINT/SIGTERM),直接修改运行状态变量,避免依赖FastAPI的shutdown事件:
from fastapi import FastAPI import asyncio import signal from contextvars import ContextVar app = FastAPI() # 使用ContextVar保证线程安全,避免信号处理器在非主线程运行时的变量冲突 running = ContextVar('running', default=True) def handle_shutdown(signum, frame): running.set(False) # 注册信号处理器,处理Ctrl+C和服务终止信号 signal.signal(signal.SIGINT, handle_shutdown) signal.signal(signal.SIGTERM, handle_shutdown) @app.get("/") async def index(): while running.get(): await asyncio.sleep(0.1)
测试验证
- 以
uvicorn module.filename:app --host 0.0.0.0启动服务; - 使用
curl http://ip:port/发起请求; - 按下
CTRL+C,服务会正常终止,不会挂起。
内容的提问来源于stack exchange,提问作者Sir l33tname
相关产品推荐
相关产品推荐

