fix: prevent InFailedSQLTransactionError in session creation
Root cause: embedding generation could break the DB transaction via a failed SQL statement. The except block caught the Python error but left the transaction in a failed state. Subsequent queries (_record_usage → subscription lookup) then failed with InFailedSQLTransactionError. Fixes: - session_embedding_service: use begin_nested() savepoint so failures don't poison the parent transaction - ai_sessions.py: add db.rollback() before _record_usage in all 3 error handlers (create, respond, pickup) to recover from broken transactions Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -139,13 +139,18 @@ async def create_session(
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception("FlowPilot session start failed: %s", e)
|
||||
await _record_usage(
|
||||
current_user, db,
|
||||
generation_type="flowpilot_start",
|
||||
input_tokens=0, output_tokens=0,
|
||||
succeeded=False, error_code=type(e).__name__,
|
||||
)
|
||||
await db.commit()
|
||||
# Rollback the failed transaction before attempting usage recording
|
||||
await db.rollback()
|
||||
try:
|
||||
await _record_usage(
|
||||
current_user, db,
|
||||
generation_type="flowpilot_start",
|
||||
input_tokens=0, output_tokens=0,
|
||||
succeeded=False, error_code=type(e).__name__,
|
||||
)
|
||||
await db.commit()
|
||||
except Exception:
|
||||
logger.warning("Failed to record usage after session start failure", exc_info=True)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_502_BAD_GATEWAY,
|
||||
detail=f"AI provider error ({type(e).__name__}). Please try again.",
|
||||
@@ -193,15 +198,19 @@ async def respond_to_step(
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.exception("FlowPilot response failed: %s", e)
|
||||
await _record_usage(
|
||||
current_user, db,
|
||||
generation_type="flowpilot_respond",
|
||||
input_tokens=0, output_tokens=0,
|
||||
succeeded=False,
|
||||
session_id=session_id,
|
||||
error_code=type(e).__name__,
|
||||
)
|
||||
await db.commit()
|
||||
await db.rollback()
|
||||
try:
|
||||
await _record_usage(
|
||||
current_user, db,
|
||||
generation_type="flowpilot_respond",
|
||||
input_tokens=0, output_tokens=0,
|
||||
succeeded=False,
|
||||
session_id=session_id,
|
||||
error_code=type(e).__name__,
|
||||
)
|
||||
await db.commit()
|
||||
except Exception:
|
||||
logger.warning("Failed to record usage after response failure", exc_info=True)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_502_BAD_GATEWAY,
|
||||
detail=f"AI provider error ({type(e).__name__}). Please try again.",
|
||||
@@ -387,15 +396,19 @@ async def pickup_session(
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.exception("FlowPilot pickup failed: %s", e)
|
||||
await _record_usage(
|
||||
current_user, db,
|
||||
generation_type="flowpilot_pickup",
|
||||
input_tokens=0, output_tokens=0,
|
||||
succeeded=False,
|
||||
session_id=session_id,
|
||||
error_code=type(e).__name__,
|
||||
)
|
||||
await db.commit()
|
||||
await db.rollback()
|
||||
try:
|
||||
await _record_usage(
|
||||
current_user, db,
|
||||
generation_type="flowpilot_pickup",
|
||||
input_tokens=0, output_tokens=0,
|
||||
succeeded=False,
|
||||
session_id=session_id,
|
||||
error_code=type(e).__name__,
|
||||
)
|
||||
await db.commit()
|
||||
except Exception:
|
||||
logger.warning("Failed to record usage after pickup failure", exc_info=True)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_502_BAD_GATEWAY,
|
||||
detail=f"AI provider error ({type(e).__name__}). Please try again.",
|
||||
|
||||
Reference in New Issue
Block a user