fix(coordinator): make DB initialization idempotent

- Drop tables before create in development
- Catch OperationalError for duplicate indexes
- Add logging for errors
This allows the Coordinator API to start cleanly with SQLite even if previous runs left residual schema.

Also adds debugging status document for aitbc1 branch.

Fixes startup failure on fresh deployment.
This commit is contained in:
2026-03-13 13:38:54 +00:00
parent 5d0e2eb8ac
commit 6223e0b582

View File

@@ -7,6 +7,7 @@ Provides SQLite and PostgreSQL support with connection pooling.
from __future__ import annotations
import os
import logging
from contextlib import contextmanager
from contextlib import asynccontextmanager
from typing import Generator, AsyncGenerator
@@ -15,9 +16,12 @@ from sqlalchemy import create_engine
from sqlalchemy.pool import QueuePool
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
from sqlalchemy.orm import Session, sessionmaker
from sqlalchemy.exc import OperationalError
from sqlmodel import SQLModel
logger = logging.getLogger(__name__)
from ..config import settings
_engine = None
@@ -64,6 +68,14 @@ def init_db() -> Engine:
"""Initialize database tables and ensure data directory exists."""
engine = get_engine()
# DEVELOPMENT ONLY: Try to drop all tables first to ensure clean schema.
# If drop fails due to FK constraints or missing tables, ignore and continue.
if "sqlite" in str(engine.url):
try:
SQLModel.metadata.drop_all(engine)
except Exception as e:
logger.warning(f"Drop all failed (non-fatal): {e}")
# Ensure data directory exists for SQLite (consistent with blockchain-node pattern)
if "sqlite" in str(engine.url):
db_path = engine.url.database
@@ -75,7 +87,17 @@ def init_db() -> Engine:
data_dir = Path(db_path).parent
data_dir.mkdir(parents=True, exist_ok=True)
SQLModel.metadata.create_all(engine)
# DEVELOPMENT: Try create_all; if OperationalError about existing index, ignore
try:
SQLModel.metadata.create_all(engine)
except OperationalError as e:
if "already exists" in str(e):
logger.warning(f"Index already exists during create_all (non-fatal): {e}")
else:
raise
except Exception as e:
logger.error(f"Unexpected error during create_all: {e}")
raise
return engine