fix(db): 收斂 DatabaseManager PostgreSQL 連線池
All checks were successful
CD Pipeline / deploy (push) Successful in 1m35s

This commit is contained in:
OoO
2026-04-30 10:08:31 +08:00
parent 27e765668b
commit 74d64092bc
9 changed files with 103 additions and 49 deletions

View File

@@ -101,53 +101,53 @@ class DatabaseManager:
self.Session = cached['Session']
return
if DATABASE_TYPE == 'postgresql':
# PostgreSQL 模式 - 使用 config.py 的連線字串
# 連線池配置以提升穩定性
self.engine = create_engine(
effective_db_path,
echo=False,
pool_pre_ping=True, # 自動檢測斷線連線
pool_size=5, # 連線池大小
max_overflow=10, # 額外連線數
pool_recycle=1800, # 30分鐘回收連線
pool_timeout=30, # 獲取連線超時
connect_args={
'connect_timeout': 10, # 連線超時 10 秒
'options': '-c statement_timeout=60000' # SQL 超時 60 秒
if DATABASE_TYPE == 'postgresql':
# PostgreSQL 模式 - 使用 config.py 的連線字串
# V-Fix: gunicorn 多 worker 下需控制每個 process 的最大連線數。
self.engine = create_engine(
effective_db_path,
echo=False,
pool_pre_ping=True, # 自動檢測斷線連線
pool_size=2, # 每個 worker 保留少量常駐連線
max_overflow=3, # 突發上限,避免吃滿 PostgreSQL clients
pool_recycle=1800, # 30分鐘回收連線
pool_timeout=30, # 獲取連線超時
connect_args={
'connect_timeout': 10, # 連線超時 10 秒
'options': '-c statement_timeout=60000' # SQL 超時 60 秒
}
)
ensure_metadata_initialized(self.engine, use_postgres_lock=True)
self.Session = sessionmaker(bind=self.engine)
self._instance_cache[cache_key] = {
'engine': self.engine,
'Session': self.Session,
}
)
ensure_metadata_initialized(self.engine, use_postgres_lock=True)
self.Session = sessionmaker(bind=self.engine)
self._instance_cache[cache_key] = {
'engine': self.engine,
'Session': self.Session,
}
sys_log.info(f"[Database] ✅ 使用 PostgreSQL 資料庫 (連線池已優化)")
# ADR-013: 確保 AIOps 自動修復表存在並植入種子 PlayBook
self._init_autoheal_tables()
else:
# SQLite 模式 - 向後相容
if db_path is None:
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
effective_db_path = os.path.join(base_dir, 'data', 'momo_database.db')
if str(effective_db_path).startswith('sqlite://'):
sqlite_db_file = make_url(effective_db_path).database
if sqlite_db_file:
os.makedirs(os.path.dirname(sqlite_db_file), exist_ok=True)
self.engine = create_engine(effective_db_path, echo=False)
sys_log.info(f"[Database] ✅ 使用 PostgreSQL 資料庫 (連線池已收斂)")
# ADR-013: 確保 AIOps 自動修復表存在並植入種子 PlayBook
self._init_autoheal_tables()
else:
os.makedirs(os.path.dirname(effective_db_path), exist_ok=True)
self.engine = create_engine(f'sqlite:///{effective_db_path}', echo=False)
Base.metadata.create_all(self.engine)
self.Session = sessionmaker(bind=self.engine)
self._instance_cache[cache_key] = {
'engine': self.engine,
'Session': self.Session,
}
self._check_and_fix_schema()
sys_log.info(f"[Database] 使用 SQLite 資料庫: {effective_db_path}")
# SQLite 模式 - 向後相容
if db_path is None:
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
effective_db_path = os.path.join(base_dir, 'data', 'momo_database.db')
if str(effective_db_path).startswith('sqlite://'):
sqlite_db_file = make_url(effective_db_path).database
if sqlite_db_file:
os.makedirs(os.path.dirname(sqlite_db_file), exist_ok=True)
self.engine = create_engine(effective_db_path, echo=False)
else:
os.makedirs(os.path.dirname(effective_db_path), exist_ok=True)
self.engine = create_engine(f'sqlite:///{effective_db_path}', echo=False)
Base.metadata.create_all(self.engine)
self.Session = sessionmaker(bind=self.engine)
self._instance_cache[cache_key] = {
'engine': self.engine,
'Session': self.Session,
}
self._check_and_fix_schema()
sys_log.info(f"[Database] 使用 SQLite 資料庫: {effective_db_path}")
def _check_and_fix_schema(self):
"""自動檢查並修復資料庫結構 (僅限 SQLite)"""