refactor: 架构优化-后端(SQLite WAL/迁移机制/健康检查/uiautodev孤儿清理/残留提示)
- SQLite 开 WAL + busy_timeout + synchronous=NORMAL,避免多 worker 并发写锁 - 新增版本化 schema 迁移机制(SCHEMA_MIGRATIONS + app_meta 表记录版本) - 新增 /api/health 健康检查(无需登录,返回设备/任务/错误摘要) - uiautodev 用 PID 文件追踪,启动时清理上次异常退出残留的孤儿进程 - 启动时提示残留的 STF 占用(不自动释放,避免多实例误伤)
This commit is contained in:
@@ -20,6 +20,8 @@ import hashlib
|
||||
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_login import UserMixin
|
||||
from sqlalchemy import event, text
|
||||
from sqlalchemy.engine import Engine
|
||||
|
||||
from core.logger import get_logger
|
||||
|
||||
@@ -28,6 +30,19 @@ _log = get_logger("core.models")
|
||||
db = SQLAlchemy()
|
||||
|
||||
|
||||
@event.listens_for(Engine, "connect")
|
||||
def _sqlite_pragma(dbapi_connection, connection_record):
|
||||
"""SQLite 并发写优化:WAL 模式 + 忙等待超时 + 降同步级别。
|
||||
|
||||
多 worker 后台线程同时写库(任务参数/分组)时,避免 database is locked。
|
||||
"""
|
||||
cursor = dbapi_connection.cursor()
|
||||
cursor.execute("PRAGMA journal_mode=WAL")
|
||||
cursor.execute("PRAGMA busy_timeout=5000")
|
||||
cursor.execute("PRAGMA synchronous=NORMAL")
|
||||
cursor.close()
|
||||
|
||||
|
||||
class User(UserMixin, db.Model):
|
||||
"""后台用户。"""
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
@@ -164,6 +179,13 @@ class ApkFile(db.Model):
|
||||
return f"<ApkFile {self.display_name}>"
|
||||
|
||||
|
||||
# 版本化 schema 迁移:新增结构变更时在此追加 (版本号, 说明, SQL)
|
||||
# 版本号单调递增,只执行比当前 schema_version 新的迁移。
|
||||
SCHEMA_MIGRATIONS = [
|
||||
# (1, "初始 schema(由 create_all 建立,版本标记从 1 开始)", None),
|
||||
]
|
||||
|
||||
|
||||
def init_db(app):
|
||||
"""在 Flask app context 里初始化数据库 + 创建默认管理员。
|
||||
|
||||
@@ -172,10 +194,37 @@ def init_db(app):
|
||||
db.init_app(app)
|
||||
with app.app_context():
|
||||
db.create_all()
|
||||
_migrate_schema()
|
||||
_ensure_default_admin()
|
||||
_migrate_old_json()
|
||||
|
||||
|
||||
def _migrate_schema():
|
||||
"""按 SCHEMA_MIGRATIONS 顺序执行版本化迁移,记录当前 schema_version。
|
||||
|
||||
create_all 只负责首次建表;结构变更必须走迁移,避免改了模型后老库对不上。
|
||||
"""
|
||||
try:
|
||||
db.session.execute(text(
|
||||
"CREATE TABLE IF NOT EXISTS app_meta (key TEXT PRIMARY KEY, value TEXT)"))
|
||||
db.session.commit()
|
||||
cur = db.session.execute(
|
||||
text("SELECT value FROM app_meta WHERE key='schema_version'")).scalar()
|
||||
current = int(cur) if cur else 0
|
||||
for version, desc, sql in SCHEMA_MIGRATIONS:
|
||||
if version <= current:
|
||||
continue
|
||||
if sql:
|
||||
db.session.execute(text(sql))
|
||||
db.session.execute(
|
||||
text("INSERT OR REPLACE INTO app_meta(key,value) VALUES('schema_version',:v)"),
|
||||
{"v": str(version)})
|
||||
db.session.commit()
|
||||
_log.info(f"schema 迁移到版本 {version}: {desc}")
|
||||
except Exception as e:
|
||||
_log.error(f"schema 迁移失败(不阻塞启动): {e}")
|
||||
|
||||
|
||||
def _ensure_default_admin():
|
||||
"""首次启动创建默认管理员 admin/admin123。"""
|
||||
if not User.query.filter_by(username="admin").first():
|
||||
|
||||
Reference in New Issue
Block a user