from sqlalchemy import create_engine, event from sqlalchemy.orm import sessionmaker from sqlalchemy.exc import SQLAlchemyError from app.core.config import settings from app.core.logging import get_logger logger = get_logger("db.session") # Wrap in function for easier error handling and retries def create_db_engine(): # Use in-memory database if configured or as fallback if settings.USE_IN_MEMORY_DB: logger.info("Using in-memory SQLite database") db_url = "sqlite://" connect_args = {"check_same_thread": False} else: logger.info(f"Using file-based SQLite database at: {settings.SQLALCHEMY_DATABASE_URL}") db_url = settings.SQLALCHEMY_DATABASE_URL connect_args = {"check_same_thread": False} # Create engine with better error handling try: engine = create_engine( db_url, connect_args=connect_args, pool_pre_ping=True, # Ensure connections are still alive ) # Add engine event listeners for debugging @event.listens_for(engine, "connect") def on_connect(dbapi_connection, connection_record): logger.info("Database connection established") @event.listens_for(engine, "engine_connect") def on_engine_connect(connection): logger.info("Engine connected") # Test connection with engine.connect() as conn: conn.execute("SELECT 1") logger.info("Database connection test successful") return engine except SQLAlchemyError as e: logger.error(f"Database connection error: {e}", exc_info=True) # Fall back to in-memory SQLite if file access failed if not settings.USE_IN_MEMORY_DB: logger.info("Falling back to in-memory SQLite database") return create_engine( "sqlite://", connect_args={"check_same_thread": False} ) # Re-raise if in-memory DB was already the target raise # Initialize engine try: engine = create_db_engine() SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) except Exception as e: logger.error(f"Failed to initialize database engine: {e}", exc_info=True) engine = None SessionLocal = None # Dependency to get DB session def get_db(): if not SessionLocal: logger.error("Database session not initialized") raise SQLAlchemyError("Database connection failed") db = SessionLocal() try: logger.debug("DB session created") yield db except SQLAlchemyError as e: logger.error(f"Database error during session: {e}") raise finally: logger.debug("DB session closed") db.close()