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:
Scott Idem
2026-01-21 15:23:04 -05:00
parent 89bf87cb62
commit 6ca79e9a02
9 changed files with 263 additions and 833 deletions

View File

@@ -13,6 +13,8 @@ from app.log import log, logger_reset
from app import lib_sql_core
from app.lib_sql_core import sql_connect, set_last_sql_error
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
# Helper for resolving random IDs
from app.lib_redis_helpers import lookup_id_random_pop
@@ -51,26 +53,27 @@ def sql_insert(
log.error('SQL INSERT statement could not be created. Missing params.')
return False
trans = lib_sql_core.db.begin()
trans = None
try:
result_insert = lib_sql_core.db.execute(sql_insert_stmt, data)
trans.commit()
with lib_sql_core.engine.connect() as conn:
trans = conn.begin()
result_insert = conn.execute(sql_insert_stmt, data)
trans.commit()
if result_insert.rowcount == 1 and result_insert.lastrowid > 0:
return result_insert.lastrowid
return False
except IntegrityError as e:
trans.rollback()
if trans: trans.rollback()
log.error('Integrity error (likely duplicate). Returning None')
log.debug(e)
set_last_sql_error(e)
return None
except Exception as e:
trans.rollback()
if trans: trans.rollback()
log.error('Unknown exception in sql_insert. Returning False')
log.exception(e)
set_last_sql_error(e)
return False
else:
if result_insert.rowcount == 1 and result_insert.lastrowid > 0:
return result_insert.lastrowid
return False
# ### END ### API DB SQL ### sql_insert() ###
@@ -123,29 +126,35 @@ def sql_update(
else:
return False
trans = lib_sql_core.db.begin()
trans = None
try:
result_update = lib_sql_core.db.execute(sql_update_stmt, data)
trans.commit()
except OperationalError:
trans.rollback()
log.error('Operational error (gone away?). Retrying once...')
sql_connect(current_db=lib_sql_core.db)
try:
result_update = lib_sql_core.db.execute(sql_update_stmt, data)
with lib_sql_core.engine.connect() as conn:
trans = conn.begin()
result_update = conn.execute(sql_update_stmt, data)
trans.commit()
if result_update.rowcount >= 1:
return True
return None
except OperationalError:
if trans: trans.rollback()
log.error('Operational error (gone away?). Retrying once...')
sql_connect()
try:
with lib_sql_core.engine.connect() as conn:
trans = conn.begin()
result_update = conn.execute(sql_update_stmt, data)
trans.commit()
if result_update.rowcount >= 1:
return True
return None
except Exception as e:
set_last_sql_error(e)
return False
except Exception as e:
trans.rollback()
if trans: trans.rollback()
log.exception(e)
set_last_sql_error(e)
return False
else:
if result_update.rowcount >= 1:
return True
return None
# ### END ### API DB SQL ### sql_update() ###
@@ -183,13 +192,15 @@ def sql_insert_or_update(
else:
return False
trans = lib_sql_core.db.begin()
trans = None
try:
res = lib_sql_core.db.execute(stmt, data)
trans.commit()
return res.lastrowid if res.lastrowid > 0 else True
with lib_sql_core.engine.connect() as conn:
trans = conn.begin()
res = conn.execute(stmt, data)
trans.commit()
return res.lastrowid if res.lastrowid > 0 else True
except Exception as e:
trans.rollback()
if trans: trans.rollback()
log.exception(e)
return False
# ### END ### Core Help CRUD ### sql_insert_or_update() ###
@@ -286,18 +297,18 @@ def sql_select(
else:
return False
result = run_sql_select(sql=stmt, data=data)
if not result:
return [] if as_list else None
# Fetch all rows first to determine actual count reliably
try:
# Check if the result set actually contains rows before fetching
if hasattr(result, 'returns_rows') and not result.returns_rows:
log.warning("SQL Result does not return rows (ResourceClosedError prevented).")
return [] if as_list else None
rows = result.all()
with lib_sql_core.engine.connect() as conn:
result = conn.execute(stmt, data)
if not result:
return [] if as_list else None
# Fetch all rows first to determine actual count reliably
if hasattr(result, 'returns_rows') and not result.returns_rows:
log.warning("SQL Result does not return rows (ResourceClosedError prevented).")
return [] if as_list else None
rows = result.all()
except Exception as e:
log.error(f"SQL Fetch Error: {e}")
set_last_sql_error(e)
@@ -327,15 +338,15 @@ def run_sql_select(
) -> Any:
log.setLevel(log_lvl)
# print(f"Executing SQL: {sql} with data: {data}", flush=True)
try:
return lib_sql_core.db.execute(sql, data)
with lib_sql_core.engine.connect() as conn:
return conn.execute(sql, data)
except (OperationalError, ProgrammingError) as e:
log.error(f'DB Error: {e}. Retrying once...')
sql_connect(current_db=lib_sql_core.db)
sql_connect()
try:
return lib_sql_core.db.execute(sql, data)
with lib_sql_core.engine.connect() as conn:
return conn.execute(sql, data)
except Exception as e2:
set_last_sql_error(e2)
raise e2 # RAISING instead of returning False
@@ -372,8 +383,9 @@ def sql_delete(
return False
try:
result = lib_sql_core.db.execute(stmt, data) if data else lib_sql_core.db.execute(stmt)
return True if result.rowcount >= 1 else None
with lib_sql_core.engine.connect() as conn:
result = conn.execute(stmt, data) if data else conn.execute(stmt)
return True if result.rowcount >= 1 else None
except Exception as e:
log.exception(e)
return False