配置管理与应用生命周期
为什么把配置放在代码外
开发与服务器环境的数据库地址、日志设置、密钥可能不同。代码不应该因为换环境就到处修改。
环境变量来自进程运行环境;.env 是在本地保存配置文本的常见方式。pydantic-settings 可读取、转换并校验这些值。官方配置说明
安装:
powershell
python -m pip install pydantic-settings httpx完整示例:配置、缓存与 lifespan
python
from contextlib import asynccontextmanager
from functools import lru_cache
from typing import Annotated
import httpx
from fastapi import Depends, FastAPI
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
env_prefix="LEARN_",
extra="ignore",
)
app_name: str = "FastAPI 学习项目"
debug: bool = False
@lru_cache
def get_settings() -> Settings:
return Settings()
@asynccontextmanager
async def lifespan(app: FastAPI):
async with httpx.AsyncClient(timeout=5.0) as client:
app.state.http_client = client
yield
app = FastAPI(title=get_settings().app_name, lifespan=lifespan)
@app.get("/info")
def info(settings: Annotated[Settings, Depends(get_settings)]):
return {"app_name": settings.app_name, "debug": settings.debug}可在启动工作目录放置 .env:
dotenv
LEARN_APP_NAME=我的待办事项服务
LEARN_DEBUG=false也可以在 PowerShell 中设置:
powershell
$env:LEARN_APP_NAME = "我的待办事项服务"这个示例只返回公开配置。不要把整个配置对象直接返回给客户端,因为真实项目的配置中可能有密钥。
lru_cache 在这里的意义
它避免每次请求都重新读取并解析配置。缓存通常是当前进程内的,多工作进程各有自己的缓存。
配置变化后需要明确的重新加载方式,例如重启服务;不能假设编辑 .env 后所有已缓存设置立即变化。
lifespan:启动准备与关闭清理
yield 前的逻辑在接收请求前执行;退出时执行资源清理。本例进入异步客户端上下文,准备可复用客户端;关闭应用时退出上下文并关闭连接资源。
app.state 是存放应用状态的地方。这里保存的是可复用客户端,不要把一个业务事务连接保存在这里供所有请求共享。
新项目优先使用 lifespan。旧教程的 @app.on_event("startup")、shutdown 是已经不推荐的新项目方式;不要同时配置后又期待两套生命周期机制都按同样方式执行。官方生命周期说明
每个请求与整个应用的资源范围
| 范围 | 典型资源 | 常见管理方式 |
|---|---|---|
| 每次请求 | 当前用户信息、请求相关资源 | 依赖函数、yield |
| 每个应用进程 | 连接池、HTTP 客户端、模型资源 | lifespan |
| 多个进程共享 | 业务记录、分布式缓存 | 数据库、Redis 等外部系统 |
多工作进程意味着生命周期逻辑通常会在各个进程执行,不能假设全站只初始化一次。
配置文件的提交习惯
提交不包含真实秘密的 .env.example,记录需要哪些变量;真实 .env 加入版本控制忽略列表。虚拟环境、缓存、开发数据库文件也通常不提交。
本章练习
通过环境变量修改应用名称;在 lifespan 的前后分别打印“启动准备”和“关闭清理”,观察何时执行。
过关标准:能解释配置来自哪里、为什么缓存,以及请求级资源和应用级资源的区别。