chore(api): stabilize SQL core and enhance searchability
- Refactor SQL CRUD to use engine.connect() context managers for thread safety - Optimize connection pooling in lib_sql_core - Clean up app/routers/api.py to fix duplicate definitions and OpenAPI KeyError - Add 'default_qry_str' to searchable_fields for Event, Session, Presentation, Presenter, Badge, and Journal - Add 'event_location_name' to searchable_fields for Event Session - Verified 20/20 E2E success via repro_intermittent_errors.py
This commit is contained in:
@@ -9,6 +9,7 @@ from sqlalchemy import create_engine
|
||||
from app.config import settings
|
||||
|
||||
log = logging.getLogger('root')
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
# 1. Thread-local storage for capturing last SQL error message
|
||||
_sql_error_state = threading.local()
|
||||
@@ -27,29 +28,32 @@ def set_last_sql_error(error: Any):
|
||||
# 2. Initial Engine Setup
|
||||
db_uri = settings.SQLALCHEMY_DB_URI
|
||||
|
||||
engine = create_engine(
|
||||
url = db_uri,
|
||||
echo = False,
|
||||
pool_use_lifo = True,
|
||||
pool_pre_ping = True,
|
||||
pool_recycle = settings.DB['pool_recycle'],
|
||||
isolation_level = 'READ COMMITTED',
|
||||
connect_args = {'connect_timeout': settings.DB['connect_timeout']}
|
||||
)
|
||||
def create_ae_engine(uri: str):
|
||||
return create_engine(
|
||||
url = uri,
|
||||
echo = False,
|
||||
pool_size = settings.DB.get('pool_size', 10),
|
||||
max_overflow = settings.DB.get('max_overflow', 20),
|
||||
pool_use_lifo = True,
|
||||
pool_pre_ping = True,
|
||||
pool_recycle = settings.DB['pool_recycle'],
|
||||
isolation_level = 'READ COMMITTED',
|
||||
connect_args = {'connect_timeout': settings.DB['connect_timeout']}
|
||||
)
|
||||
|
||||
log.info('DB SQL Core: Initializing connection...')
|
||||
db = None
|
||||
try:
|
||||
db = engine.connect()
|
||||
log.info(f'DB SQL Core: Connected to database: {db_uri}')
|
||||
except Exception:
|
||||
log.exception('DB SQL Core: Could not connect to database.')
|
||||
engine = create_ae_engine(db_uri)
|
||||
|
||||
# DEPRECATED: Global shared 'db' connection. Use engine.connect() in context managers instead.
|
||||
# Keeping for legacy compatibility but will phase out usage in crud lib.
|
||||
db = engine.connect()
|
||||
|
||||
log.info('DB SQL Core: Initializing engine...')
|
||||
|
||||
|
||||
# 3. Connection Management Logic
|
||||
def reconnect_db() -> bool:
|
||||
"""
|
||||
Re-initializes the global database engine and connection using current settings.
|
||||
Re-initializes the global database engine using current settings.
|
||||
Useful after bootstrapping new credentials from the 'cfg' table.
|
||||
"""
|
||||
global engine, db, db_uri
|
||||
@@ -61,28 +65,16 @@ def reconnect_db() -> bool:
|
||||
log.info("DB SQL Core: Disposed of previous database engine.")
|
||||
|
||||
db_uri = settings.SQLALCHEMY_DB_URI
|
||||
engine = create_engine(
|
||||
url = db_uri,
|
||||
echo = False,
|
||||
pool_use_lifo = True,
|
||||
pool_pre_ping = True,
|
||||
pool_recycle = settings.DB['pool_recycle'],
|
||||
isolation_level = 'READ COMMITTED',
|
||||
connect_args = {'connect_timeout': settings.DB['connect_timeout']}
|
||||
)
|
||||
engine = create_ae_engine(db_uri)
|
||||
db = engine.connect()
|
||||
log.info(f"DB SQL Core: Database connection re-established successfully: {db_uri}")
|
||||
log.info(f"DB SQL Core: Database engine re-established successfully: {db_uri}")
|
||||
return True
|
||||
except Exception:
|
||||
log.exception("DB SQL Core: FAILED to refresh database connection!")
|
||||
log.exception("DB SQL Core: FAILED to refresh database engine!")
|
||||
return False
|
||||
|
||||
def sql_connect(current_db=None, log_lvl: int = logging.INFO) -> bool:
|
||||
|
||||
"""Refreshes the global database connection."""
|
||||
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
log.info('DB SQL Core: Refreshing database connection via sql_connect...')
|
||||
|
||||
return reconnect_db()
|
||||
Reference in New Issue
Block a user