wu981526092 commited on
Commit
63b0e81
Β·
1 Parent(s): fa515bb

πŸ”§ Fix SQLAlchemy Connection Pool Error in HF Spaces

Browse files

❌ Critical Issue Fixed:
β€’ AssertionError: can't 'checkout' a detached connection fairy
β€’ Multiple 500 errors on /api/traces/ endpoint
β€’ Database connection pool failures in async environment

🎯 Root Cause Analysis:
β€’ sqlite:///:memory: doesn't work well with FastAPI async operations
β€’ In-memory databases create separate instances per connection
β€’ Connection pool management conflicts in multi-threaded environment
β€’ SQLAlchemy connection fairy detachment issues

⚑ Solution Implemented:
β€’ Replaced in-memory database with temporary file database
β€’ Enhanced SQLite engine configuration for async operations
β€’ Added proper connection pool settings:
- pool_pre_ping=True (verify connections before use)
- pool_recycle=3600 (recycle connections every hour)
- timeout=30, isolation_level=None (autocommit mode)
β€’ Each HF Spaces session gets unique temporary database file

πŸ”’ Privacy Protection Maintained:
β€’ Still provides user isolation (unique temp file per session)
β€’ Data cleared on container restart
β€’ No cross-user data sharing
β€’ Better reliability than in-memory approach

πŸš€ Expected Results:
β€’ /api/traces/ endpoint should work without 500 errors
β€’ Stable database connections in async environment
β€’ Better performance and reliability
β€’ Maintained user privacy and data isolation

Files changed (2) hide show
  1. backend/app.py +2 -1
  2. backend/database/__init__.py +21 -7
backend/app.py CHANGED
@@ -80,8 +80,9 @@ async def startup_event():
80
 
81
  # Show database type info
82
  if os.getenv("SPACE_ID"):
83
- logger.info("πŸ”’ HF Spaces: Using in-memory database for user privacy")
84
  logger.info("πŸ“ Note: Data will be cleared when container restarts")
 
85
  else:
86
  logger.info("πŸ’Ύ Local development: Using persistent database")
87
 
 
80
 
81
  # Show database type info
82
  if os.getenv("SPACE_ID"):
83
+ logger.info("πŸ”’ HF Spaces: Using temporary file database for user privacy")
84
  logger.info("πŸ“ Note: Data will be cleared when container restarts")
85
+ logger.info("πŸ›‘οΈ User isolation: Each session has its own database")
86
  else:
87
  logger.info("πŸ’Ύ Local development: Using persistent database")
88
 
backend/database/__init__.py CHANGED
@@ -11,22 +11,36 @@ from sqlalchemy.orm import sessionmaker, scoped_session
11
  # Get the absolute path to the project root directory
12
  ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
13
 
14
- # Database URL - Use in-memory SQLite for HF Spaces to avoid data sharing between users
15
  # This ensures each container restart gets a fresh database
16
  import uuid
 
17
  session_id = str(uuid.uuid4())[:8]
18
 
19
- # For HF Spaces: Use in-memory database to prevent user data sharing
20
- # For local development: Use file database
21
  if os.getenv("SPACE_ID"): # HF Spaces environment
22
- DATABASE_URL = "sqlite:///:memory:"
23
- print(f"πŸ”’ HF Spaces: Using in-memory database (session: {session_id})")
 
 
 
24
  else:
25
  DATABASE_URL = f"sqlite:///{os.path.join(ROOT_DIR, 'datasets/db/agent_monitoring.db')}"
26
  print(f"πŸ’Ύ Local: Using persistent database")
27
 
28
- # Create engine
29
- engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
 
 
 
 
 
 
 
 
 
 
30
 
31
  # Create session factory
32
  SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
 
11
  # Get the absolute path to the project root directory
12
  ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
13
 
14
+ # Database URL - Use temporary file SQLite for HF Spaces to avoid data sharing between users
15
  # This ensures each container restart gets a fresh database
16
  import uuid
17
+ import tempfile
18
  session_id = str(uuid.uuid4())[:8]
19
 
20
+ # For HF Spaces: Use temporary file database to prevent user data sharing
21
+ # For local development: Use persistent file database
22
  if os.getenv("SPACE_ID"): # HF Spaces environment
23
+ # Use temporary file instead of in-memory to avoid connection pool issues
24
+ temp_db_path = f"/tmp/agentgraph_{session_id}.db"
25
+ DATABASE_URL = f"sqlite:///{temp_db_path}"
26
+ print(f"πŸ”’ HF Spaces: Using temporary database (session: {session_id})")
27
+ print(f"πŸ“ Database path: {temp_db_path}")
28
  else:
29
  DATABASE_URL = f"sqlite:///{os.path.join(ROOT_DIR, 'datasets/db/agent_monitoring.db')}"
30
  print(f"πŸ’Ύ Local: Using persistent database")
31
 
32
+ # Create engine with proper SQLite configuration for async operations
33
+ engine = create_engine(
34
+ DATABASE_URL,
35
+ connect_args={
36
+ "check_same_thread": False,
37
+ "timeout": 30,
38
+ "isolation_level": None, # Autocommit mode
39
+ },
40
+ pool_pre_ping=True, # Verify connections before use
41
+ pool_recycle=3600, # Recycle connections every hour
42
+ echo=False # Disable SQL logging for production
43
+ )
44
 
45
  # Create session factory
46
  SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)