| title | SPEC-11: Basic Memory API Performance Optimization | |||||
|---|---|---|---|---|---|---|
| type | spec | |||||
| permalink | specs/spec-11-basic-memory-api-performance-optimization | |||||
| tags |
|
The Basic Memory API experiences significant performance issues in cloud environments due to expensive per-request initialization. MCP tools making HTTP requests to the API suffer from 350ms-2.6s latency overhead before any actual operation occurs.
Root Cause Analysis:
- GitHub Issue #82 shows repeated initialization sequences in logs (16:29:35 and 16:49:58)
- Each MCP tool call triggers full database initialization + project reconciliation
get_engine_factory()dependency callsdb.get_or_create_db()on every requestreconcile_projects_with_config()runs expensive sync operations repeatedly
Performance Impact:
- Database connection setup: ~50-100ms per request
- Migration checks: ~100-500ms per request
- Project reconciliation: ~200ms-2s per request
- Total overhead: ~350ms-2.6s per MCP tool call
This creates compounding effects with tenant auto-start delays and increases timeout risk in cloud deployments.
Github issue: https://github.com/basicmachines-co/basic-memory-cloud/issues/82
This optimization affects the core basic-memory repository components:
- API Lifespan Management (
src/basic_memory/api/app.py)
- Cache database connections in app state during startup
- Avoid repeated expensive initialization
- Dependency Injection (
src/basic_memory/deps.py)
- Modify
get_engine_factory()to use cached connections - Eliminate per-request database setup
- Initialization Service (
src/basic_memory/services/initialization.py)
- Add caching/throttling to project reconciliation
- Skip expensive operations when appropriate
- Configuration (
src/basic_memory/config.py)
- Add optional performance flags for cloud environments
Backwards Compatibility: All changes must be backwards compatible with existing CLI and non-cloud usage.
Problem: get_engine_factory() calls db.get_or_create_db() per request
Solution: Cache database engine/session in app state during lifespan
- Modify API Lifespan (
api/app.py):
@asynccontextmanager
async def lifespan(app: FastAPI):
app_config = ConfigManager().config
await initialize_app(app_config)
# Cache database connection in app state
engine, session_maker = await db.get_or_create_db(app_config.database_path)
app.state.engine = engine
app.state.session_maker = session_maker
# ... rest of startup logic- Modify Dependency Injection (deps.py):
async def get_engine_factory(
request: Request
) -> tuple[AsyncEngine, async_sessionmaker[AsyncSession]]:
"""Get cached engine and session maker from app state."""
return request.app.state.engine, request.app.state.session_makerPhase 2: Optimize Project Reconciliation (Secondary - 20% of gains)
Problem: reconcile_projects_with_config() runs expensive sync repeatedly Solution: Add module-level caching with time-based throttling
- Add Reconciliation Cache (services/initialization.py):
_project_reconciliation_completed = False
_last_reconciliation_time = 0
async def reconcile_projects_with_config(app_config, force=False):
# Skip if recently completed (within 60 seconds) unless forced
if recently_completed and not force:
return
# ... existing logic
Phase 3: Cloud Environment Flags (Optional)
Problem: Force expensive initialization in production environments Solution: Add skip flags for cloud/stateless deployments
- Add Config Flag (config.py): skip_initialization_sync: bool = Field(default=False)
- Configure in Cloud (basic-memory-cloud integration): BASIC_MEMORY_SKIP_INITIALIZATION_SYNC=true
How to Evaluate
Success Criteria
- Performance Metrics (Primary):
- MCP tool response time reduced by 50%+ (measure before/after)
- Database connection overhead eliminated (0ms vs 50-100ms)
- Migration check overhead eliminated (0ms vs 100-500ms)
- Project reconciliation overhead reduced by 90%+
- Load Testing:
- Concurrent MCP tool calls maintain performance
- No memory leaks in cached connections
- Database connection pool behaves correctly
- Functional Correctness:
- All existing API endpoints work identically
- MCP tools maintain full functionality
- CLI operations unaffected
- Database migrations still execute properly
- Backwards Compatibility:
- No breaking changes to existing APIs
- Config changes are optional with safe defaults
- Non-cloud deployments work unchanged
Testing Strategy
Performance Testing:
time basic-memory-mcp-tools write_note "test" "content" "folder"
time basic-memory-mcp-tools write_note "test" "content" "folder"
Load Testing:
for i in {1..10}; do basic-memory-mcp-tools search "test" & done wait
Regression Testing:
just test
Validation Checklist
- Phase 1 Complete: Database connections cached, dependency injection optimized
- Performance Benchmark: 50%+ improvement in MCP tool response times
- Memory Usage: No leaks in cached connections over 24h+ periods
- Stress Testing: 100+ concurrent requests maintain performance
- Backwards Compatibility: All existing functionality preserved
- Documentation: Performance optimization documented in README
- Cloud Integration: basic-memory-cloud sees performance benefits
Implementation Date: 2025-09-26
Branch: feature/spec-11-api-performance-optimization
Commit: 771f60b
Files Modified:
src/basic_memory/api/app.py- Added database connection caching in app.statesrc/basic_memory/deps.py- Updated get_engine_factory() to use cached connectionssrc/basic_memory/config.py- Added skip_initialization_sync configuration flag
Implementation Details:
- API Lifespan Caching: Database engine and session_maker cached in app.state during startup
- Dependency Injection Optimization: get_engine_factory() now returns cached connections instead of calling get_or_create_db()
- Project Reconciliation Removal: Eliminated expensive reconcile_projects_with_config() from API startup
- CLI Fallback Preserved: Non-API contexts continue to work with fallback database initialization
Live Testing Results (2025-09-26 14:03-14:09):
| Operation | Before | After | Improvement |
|---|---|---|---|
read_note |
350ms-2.6s | 20ms | 95-99% faster |
edit_note |
350ms-2.6s | 218ms | 75-92% faster |
search_notes |
350ms-2.6s | <500ms | Responsive |
list_memory_projects |
N/A | <100ms | Fast |
Key Achievements:
- ✅ 95-99% improvement in read operations (primary workflow)
- ✅ 75-92% improvement in edit operations
- ✅ Zero overhead for project switching
- ✅ Database connection overhead eliminated (0ms vs 50-100ms)
- ✅ Project reconciliation delays removed from API requests
- ✅ <500ms target achieved for all operations except write (which includes file sync)
- All existing functionality preserved
- CLI operations unaffected
- Fallback for non-API contexts maintained
- No breaking changes to existing APIs
- Optional configuration with safe defaults
- Integration tests passing
- Type checking clear
- Linting checks passed
- Live testing with real MCP tools successful
- Multi-project workflows validated
- Rapid project switching validated
Implementation Priority:
- ✅ Phase 1 COMPLETED: Database connection caching provides 95%+ performance gains
- ⚪ Phase 2 NOT NEEDED: Project reconciliation removal achieved the goals
- ⚪ Phase 3 INCLUDED: skip_initialization_sync flag added
Risk Mitigation:
- ✅ All changes backwards compatible implemented
- ✅ Gradual implementation successful (Phase 1 → validation)
- ✅ Easy rollback via configuration flags available
Cloud Integration:
- ✅ This optimization directly addresses basic-memory-cloud issue #82
- ✅ Changes in core basic-memory will benefit all cloud tenants
- ✅ No changes needed in basic-memory-cloud itself
Result: SPEC-11 performance optimizations successfully implemented and validated. The 95-99% improvement in MCP tool response times exceeds the original 50-80% target, providing exceptional performance gains for cloud deployments and local usage.