Files
mindfulness/server/app/core/config.py
2026-02-03 00:23:48 +08:00

109 lines
3.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from functools import lru_cache
from pathlib import Path
from typing import Literal, Optional
from pydantic import ValidationError
from pydantic_settings import BaseSettings, SettingsConfigDict
def _guess_env_file(app_env: str) -> Optional[str]:
"""
根据 APP_ENV 选择 env 文件。
说明:
- `.env.dev` / `.env.prod` 不进入仓库,通常由运维在部署时放到 `server/` 目录
- 如果文件不存在,则返回 None让系统从“真实环境变量”读取
"""
base_dir = Path(__file__).resolve().parents[2] # .../server/app -> .../server
candidates = {
"dev": base_dir / ".env.dev",
"prod": base_dir / ".env.prod",
}
p = candidates.get(app_env)
if p and p.exists():
return str(p)
return None
class Settings(BaseSettings):
"""
应用配置(统一从环境变量读取)。
注意:请不要把真实账号密码写入仓库;使用 `.env.dev/.env.prod` 或部署系统注入。
"""
app_env: Literal["dev", "prod"] = "dev"
app_name: str = "mindfulness-server"
app_host: str = "0.0.0.0"
app_port: int = 8000
database_url: str
redis_url: str
celery_broker_url: str
celery_result_backend: Optional[str] = None
model_config = SettingsConfigDict(
env_prefix="",
case_sensitive=False,
extra="ignore",
)
@lru_cache
def get_settings() -> Settings:
"""
获取配置(带缓存)。
加载顺序:
- 优先使用 `.env.dev/.env.prod`(若存在)
- 否则使用系统环境变量
"""
import os
env = os.getenv("APP_ENV", "dev").strip() or "dev"
env_file = _guess_env_file(env)
try:
return Settings(_env_file=env_file)
except ValidationError as e:
# 给出更可执行的错误信息,避免只看到一串校验栈。
missing_fields: list[str] = []
for err in e.errors():
if err.get("type") == "missing":
loc = err.get("loc") or ()
if loc:
missing_fields.append(str(loc[0]))
# 将字段名映射为常见的环境变量名(默认规则:字段名大写)
missing_env_keys = [f.upper() for f in missing_fields] if missing_fields else []
env_file_hint = env_file or f".env.{env}(未找到,已回退到系统环境变量)"
required_hint = (
"".join(missing_env_keys)
if missing_env_keys
else "DATABASE_URL、REDIS_URL、CELERY_BROKER_URL"
)
msg = (
"应用启动失败:缺少必填配置。\n\n"
f"- 当前 APP_ENV{env}\n"
f"- 期望读取的 env 文件:{env_file_hint}\n"
f"- 缺少的环境变量:{required_hint}\n\n"
"修复方式(任选其一):\n"
"1) 直接注入环境变量(推荐):\n"
" - DATABASE_URL=...\n"
" - REDIS_URL=...\n"
" - CELERY_BROKER_URL=...\n"
"2) 使用 env 文件:在 `server/` 下准备 `.env.dev` 或 `.env.prod`KEY=value 格式),\n"
" 本地可通过 `server/run.sh --env dev|prod` 自动加载Docker 运行可用 `--env-file` 传入。\n"
)
# 不附带原始 ValidationError 的异常上下文,减少日志噪音;
# msg 已包含缺失项与修复方式,足够定位问题。
raise RuntimeError(msg) from None