fix(db): eliminate SQLite brain-split, force PostgreSQL

Root cause: Worker used SQLITE_DATABASE_URL causing "no such table: incidents"
because each Pod had isolated SQLite file, not shared PostgreSQL.

Fixes:
- db/base.py: Use DATABASE_URL (PostgreSQL) instead of SQLITE_DATABASE_URL
- Added SQLite prohibition guard with logging
- Added pool_size and pool_pre_ping for production stability

New: packages/lewooogo-data PgMemoryProvider (Phase 6.4d)
- Episodic Memory implementation for PostgreSQL
- init_pg_engine() with auto table creation
- SQLite forbidden by Commander's decree

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
OG T
2026-03-23 10:02:43 +08:00
parent 9f353343c9
commit 1576f2ab20
4 changed files with 314 additions and 23 deletions

View File

@@ -5,9 +5,12 @@ CTO-201: Async SQLAlchemy setup
Features:
- SQLAlchemy 2.0 async engine
- aiosqlite for local dev
- PostgreSQL-ready (asyncpg)
- PostgreSQL (asyncpg) - 188 PostgreSQL
- Session dependency injection
統帥鐵律 2026-03-23:
- 絕對禁止 SQLite
- 所有 Episodic Memory 必須使用 PostgreSQL
"""
from collections.abc import AsyncGenerator
@@ -42,18 +45,30 @@ _session_factory: async_sessionmaker[AsyncSession] | None = None
def get_engine() -> AsyncEngine:
"""Get or create async engine"""
"""
Get or create async engine
統帥鐵律 2026-03-23:
- 使用 DATABASE_URL (PostgreSQL)
- 絕對禁止 SQLite
"""
global _engine
if _engine is None:
# SQLite 需要特殊處理
connect_args = {}
if settings.SQLITE_DATABASE_URL.startswith("sqlite"):
connect_args["check_same_thread"] = False
database_url = settings.DATABASE_URL
# 統帥鐵律: 禁止 SQLite
if "sqlite" in database_url.lower():
import structlog
logger = structlog.get_logger(__name__)
logger.error("sqlite_forbidden", message="SQLite is FORBIDDEN. Using PostgreSQL default.")
database_url = "postgresql+asyncpg://awoooi:changeme@192.168.0.188:5432/awoooi_prod"
_engine = create_async_engine(
settings.SQLITE_DATABASE_URL,
database_url,
echo=settings.DEBUG,
connect_args=connect_args,
pool_size=10,
max_overflow=20,
pool_pre_ping=True,
)
return _engine

View File

@@ -79,9 +79,10 @@ async def lifespan(_app: FastAPI) -> AsyncGenerator[None, None]:
kubeconfig=settings.KUBECONFIG_PATH,
)
# CTO-201: Initialize SQLite database
# CTO-201: Initialize PostgreSQL database (統帥鐵律: 禁止 SQLite)
await init_db()
logger.info("database_initialized", url=settings.SQLITE_DATABASE_URL)
db_url = settings.DATABASE_URL
logger.info("database_initialized", url=db_url.split("@")[-1] if "@" in db_url else db_url)
# Phase 5: Initialize HTTP Clients (ClickHouse, Ollama)
# 統帥鐵律: 連線池在啟動時建立,關閉時回收