feat: 数据库连接层改造——库目标由 .env 装配 + 环境防呆(迁 MySQL 第一步)
为把数据库从单文件 SQLite 迁到 MySQL 5.7 铺路。本期不改后端: DB_HOST 为空时仍走 SQLite,本地开发无感。 - config.py: 新增 DEPLOY_ENV(默认 dev)与 DB_HOST/PORT/USER/PASSWORD/NAME/ CHARSET/COLLATION、DATABASE_URL、两个逃生阀(DB_ALLOW_ENV_MISMATCH / DB_ALLOW_SQLITE_FALLBACK) - core/db_config.py(新增): URI 组装;按方言分叉的引擎参数(utf8mb4、 pool_pre_ping、pool_recycle=1800、READ COMMITTED、STRICT_TRANS_TABLES); 连接探活;app_meta 方言中立读写(MySQL 里 key 是保留字,需反引号) - 防混库三层: ①库名与环境绑定(dev→auto_control_dev / prod→auto_control) ②库标签 app_meta.deployment_env 与 .env 声明比对 ③启动横幅打印当前库 (生产用 WARNING 级)。不符直接拒绝启动并说明两边分别是什么 - web_server.py: 硬编码 sqlite URI → db_config;配置错在装配期就 exit 2; init_db 之后跑库标签校验 + 横幅 - core/models.py: PRAGMA 监听器加 sqlite 类型守卫——它挂在 Engine 基类上, MySQL 连接执行 PRAGMA 会直接导致建连失败 - requirements.txt 加 PyMySQL;scripts/start.sh 依赖守卫加 pymysql, 并在 exec 前打印 DEPLOY_ENV/DB_NAME/DB_HOST - .env.example 新增「数据库」段;DEVELOPMENT.md §4.1/4.2、DEPLOY.md §2.2 同步 验证: 用 DATABASE_URL 指向 users.db 的一致快照副本跑通主要只读接口 (health/devices/jobs/pool/groups/discovery/summary 全 200,app_meta 读写正常); DEPLOY_ENV=prod 且无 DB_HOST 时退出码 2;开 DB_ALLOW_SQLITE_FALLBACK 后可回退。
This commit is contained in:
+20
-2
@@ -33,8 +33,17 @@ if not os.environ.get("WEB_SECRET_KEY"):
|
||||
app.config["SECRET_KEY"] = _web_secret
|
||||
# debug=False 时模板默认不自动重载,开发期改 HTML 需重启才生效;这里显式开启
|
||||
app.config["TEMPLATES_AUTO_RELOAD"] = True
|
||||
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)), "data", "users.db")
|
||||
# 数据库目标与连接参数统一由 core/db_config 装配(.env 的 DEPLOY_ENV / DB_* 决定)。
|
||||
# 这里就把配置校验做完:连不上、环境与库名不匹配 → 直接拒绝启动,不要带着错配置跑起来。
|
||||
from core import db_config
|
||||
try:
|
||||
_DB_URI = db_config.build_db_uri()
|
||||
db_config.check_connection(_DB_URI)
|
||||
except db_config.DBConfigError as _e:
|
||||
_log.error("数据库配置校验失败,拒绝启动:\n%s", _e)
|
||||
raise SystemExit(2)
|
||||
app.config["SQLALCHEMY_DATABASE_URI"] = _DB_URI
|
||||
app.config["SQLALCHEMY_ENGINE_OPTIONS"] = db_config.engine_options(_DB_URI)
|
||||
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
|
||||
|
||||
login_manager = LoginManager(app)
|
||||
@@ -51,6 +60,15 @@ except Exception as _e:
|
||||
|
||||
# 先初始化数据库(含旧 JSON 迁移),再创建 TaskManager(需要 app context 读写 DB)
|
||||
init_db(app)
|
||||
# 库环境标签校验 + 启动横幅:每次启动都明确写出「现在连的是哪个库」,
|
||||
# 避免在不知情的情况下对着生产库操作(app_meta 表要存在,所以放在 init_db 之后)
|
||||
try:
|
||||
with app.app_context(): # db.engine / app_meta 读取都需要 app context
|
||||
db_config.verify_deployment_label()
|
||||
db_config.print_banner()
|
||||
except db_config.DBConfigError as _e:
|
||||
_log.error("数据库环境校验失败,拒绝启动:\n%s", _e)
|
||||
raise SystemExit(2)
|
||||
# 设备池(本地清单 + adb 在线状态):任务调度的数据源
|
||||
from core import device_pool
|
||||
device_pool.init_app(app)
|
||||
|
||||
Reference in New Issue
Block a user