PMFlow/backend/app/main_db_guard.py

92 lines
3.0 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.

"""Database dialect guard helpers for app startup."""
from __future__ import annotations
import os
from .core.config import settings
from .core.logging import get_logger
logger = get_logger(__name__)
def is_missing_table_error(exc: Exception) -> bool:
text = str(exc).lower()
return (
"no such table" in text
or "undefined table" in text
or "relation" in text and "does not exist" in text
)
def normalize_dialect(value: str) -> str:
raw = str(value or "").strip().lower()
if not raw:
return ""
if raw.startswith("postgres"):
return "postgresql"
if raw.startswith("mysql"):
return "mysql"
if "+" in raw:
raw = raw.split("+", 1)[0]
if ":" in raw:
raw = raw.split(":", 1)[0]
return raw
def mask_db_url(url: str) -> str:
value = str(url or "").strip()
if "@" not in value:
return value
prefix, suffix = value.split("@", 1)
if "://" not in prefix:
return f"***@{suffix}"
scheme, creds = prefix.split("://", 1)
user = creds.split(":", 1)[0] if ":" in creds else creds
return f"{scheme}://{user}:***@{suffix}"
def check_database_dialect_guard(sync_conn) -> None:
configured = normalize_dialect(settings.database_url)
actual = normalize_dialect(sync_conn.dialect.name)
expected = normalize_dialect(os.getenv("PMFLOW_EXPECTED_DB_DIALECT", "postgresql")) or "postgresql"
env_urls = [
os.getenv("DATABASE_URL", ""),
os.getenv("SQLALCHEMY_DATABASE_URL", ""),
os.getenv("SYNC_DATABASE_URL", ""),
]
configured_families = {normalize_dialect(item) for item in env_urls if str(item or "").strip()}
configured_families.discard("")
logger.info(
"database_dialect_guard",
configured=configured,
actual=actual,
expected=expected or "unset",
database_url=mask_db_url(settings.database_url),
)
print(
"[DB-Guard] "
f"configured={configured}, actual={actual}, expected={expected or 'unset'}, "
f"url={mask_db_url(settings.database_url)}"
)
if configured != "postgresql":
raise RuntimeError(f"DATABASE_URL 必须为 PostgreSQL,当前 configured={configured or 'unset'}。")
if actual != "postgresql":
raise RuntimeError(f"运行时数据库必须为 PostgreSQL,当前 actual={actual or 'unset'}。")
if configured and actual and configured != actual:
raise RuntimeError(
f"数据库方言不一致: configured={configured}, actual={actual}。"
"请确保同一服务只连接单一数据库方言。"
)
if expected and actual and expected != actual:
raise RuntimeError(
f"数据库方言与 PMFLOW_EXPECTED_DB_DIALECT 不一致: expected={expected}, actual={actual}。"
)
if len(configured_families) > 1:
raise RuntimeError(
f"检测到多种数据库方言配置: {sorted(configured_families)}。"
"禁止同一服务混用多数据库方言。"
)