
当 fastapi 应用在 docker 中因任务异常主动发送 sigterm 时,容器未按预期重启,根本原因在于 uvicorn 主进程未真正退出 —— 需通过正确终止主事件循环或进程组实现可靠重启。
当 fastapi 应用在 docker 中因任务异常主动发送 sigterm 时,容器未按预期重启,根本原因在于 uvicorn 主进程未真正退出 —— 需通过正确终止主事件循环或进程组实现可靠重启。
在 FastAPI + Docker 场景中,仅调用 os.kill(os.getpid(), signal.SIGTERM) 并不能保证容器重启,原因如下:
- Uvicorn 默认以多进程模式(如 --workers 1 或默认单进程)运行,但其主进程(master)与工作进程(worker)职责分离;
- os.kill(os.getpid(), signal.SIGTERM) 仅终止当前 Python 线程/协程所在的工作进程,而 Uvicorn 主进程仍存活,Docker 认为容器“仍在运行”,因此不触发 restart: always 策略;
- docker-compose.yml 中的 restart: always 仅在容器主进程退出(exit code ≠ 0 或被 kill)时生效,而非任意子进程终止。
✅ 正确做法是:确保整个 Uvicorn 进程(主进程)干净退出。推荐以下两种经验证方案:
方案一:优雅退出主事件循环(推荐)
修改 startup_event,避免手动发信号,改用 sys.exit() 或抛出可被捕获的异常,并配合 uvicorn 的 --reload(开发)或标准启动方式(生产):
import sys
import logging
import asyncio
from fastapi import FastAPI
app = FastAPI()
@app.on_event("startup")
async def startup_event() -> None:
logging.info("VP: Starting Server")
task = asyncio.create_task(task_func())
try:
await task
except Exception as error:
logging.error(f"Unrecoverable error in task_func: {error}")
logging.info("Triggering container restart via clean exit...")
# ✅ 关键:退出整个进程(Uvicorn 主进程将捕获并终止)
sys.exit(1) # Docker 将收到 exit code 1,触发 restart: always
@app.on_event("shutdown")
async def shutdown_event() -> None:
logging.info("Shutting down gracefully")
⚠️ 注意事项:
- sys.exit(1) 在 Uvicorn 主进程中会终止整个服务(非仅协程),Docker 能正确感知;
- 确保 docker-compose.yml 使用标准启动命令(如 command: ["uvicorn", "main:app", "--host", "0.0.0.0:8000"]),避免 --reload(仅用于开发);
- 若使用 Gunicorn + Uvicorn 组合部署,需确保 gunicorn 的 --preload 和 --max-startup-time 配置合理,防止主进程僵死。
方案二:健康检查驱动的主动重启(适用于 Kubernetes 或高级编排)
如原答案所述,补充 /status/health 端点并结合容器编排平台的探针机制,是一种更健壮、可观测的方案:
from fastapi import APIRouter, HTTPException
from typing import Dict
status_router = APIRouter(prefix="/status", tags=["Status"])
@status_router.get("/health")
def health() -> Dict[str, str]:
return {"status": "ok"} # 始终返回 200,表示进程存活
@status_router.get("/readiness")
async def readiness() -> Dict[str, str]:
# 可扩展为检查 DB、缓存、外部依赖等
if await check_critical_dependencies():
return {"status": "ok"}
raise HTTPException(status_code=503, detail="Service not ready")
在 docker-compose.yml 中启用健康检查(Docker 20.10+ 支持):
events_consumer:
restart: always
build:
context: ./events_consumer
target: dev
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/status/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 40s
? 总结:
- 根本解法:让 Uvicorn 主进程真实退出(sys.exit(1) 或未捕获的异常),而非仅杀 worker 进程;
- 工程最佳实践:结合健康检查(health/readiness)提升可观测性,尤其在 Kubernetes 环境中;
- 避坑提示:避免在 on_event("startup") 中阻塞 await 长时间任务——应交由后台任务管理器(如 Celery、Redis Queue)或确保异常能穿透至主进程层级。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










