Files
ALwrity/docs/TXTAI_NON_BLOCKING_FIX.md
ajaysi 651bd2b5f0 fix: Fix Unicode encoding issue in backend startup script
- Changed rocket emoji to ASCII [*] for Windows CP1252 compatibility
- This allows the backend to start without UnicodeEncodeError on Windows
2026-03-09 16:25:56 +05:30

4.0 KiB

TxtaiIntelligenceService Non-Blocking Initialization Fix

Problem

When users accessed the dashboard, the application would display "Loading weights" messages that:

  1. Blocked other API services from responding
  2. Occurred on every dashboard refresh (not just at startup)
  3. Prevented users from interacting with the application

The "Loading weights" messages indicated that the embedding model was being loaded synchronously in the main request thread, blocking the event loop.

Root Cause

The TxtaiIntelligenceService was initialized synchronously when index_content() was called:

  • Each dashboard refresh triggered _index_tasks_to_sif()
  • This function called TxtaiIntelligenceService(user_id)
  • The initialization loaded embedding weights synchronously
  • This blocked the FastAPI event loop, preventing other requests from being processed

Solution

1. Background Thread Initialization

  • Modified _ensure_initialized() to spawn a background thread instead of blocking
  • The service initialization now happens in a daemon thread while the API returns immediately
  • Prevents the event loop from being blocked
def _ensure_initialized(self):
    if self._initialization_in_progress:
        return  # Skip if already initializing
    
    self._initialization_in_progress = True
    thread = threading.Thread(target=self._initialize_embeddings, daemon=True)
    thread.start()

2. Non-Blocking API Responses

  • Updated index_content() to return immediately without waiting for initialization
  • If service isn't initialized, it logs a message and returns gracefully
  • Indexing will happen in background once weights are loaded
async def index_content(self, items):
    if not self._initialized and not self._initialization_in_progress:
        self._ensure_initialized()  # Start in background
        return  # Return immediately
    
    if not self._initialized:
        return  # Initialization still in progress

3. Initialization Tracking

  • Added _initialization_in_progress flag to track initialization state
  • Prevents duplicate initialization attempts
  • Uses asyncio locks for thread-safe initialization if needed later

4. Graceful Error Handling

  • Background indexing failures are logged but don't crash the API
  • API always responds quickly regardless of initialization state

Files Modified

  1. backend/services/intelligence/txtai_service.py

    • Added threading import for background initialization
    • Implemented non-blocking _ensure_initialized()
    • Added _ensure_initialized_async() for future truly async operations
    • Modified index_content() to return immediately without blocking
  2. backend/api/today_workflow.py

    • Updated _index_tasks_to_sif() with better error handling
    • Added comments explaining non-blocking behavior

Benefits

  1. Dashboard loads instantly - No more "Loading weights" blocking the UI
  2. Non-blocking operations - Other API services can respond while weights load
  3. Single initialization - Weights are only loaded once per user session, in background
  4. Graceful degradation - If indexing fails, API still responds normally
  5. Better user experience - UI is responsive even during first-time weight loading

Testing

The fix can be verified by:

  1. Restarting the backend
  2. Refreshing the dashboard multiple times
  3. Observing that there's no "Loading weights" blocking message
  4. Verifying other API endpoints respond quickly

Technical Details

  • Thread Safety: Uses daemon threads which don't prevent process shutdown
  • Event Loop: Background initialization doesn't block the FastAPI event loop
  • Singleton Pattern: Maintained - each user gets one TxtaiIntelligenceService instance
  • Caching: Existing semantic cache functionality is preserved

Future Improvements

  1. Could implement pre-initialization in startup event for common users
  2. Could add metrics to track initialization completion
  3. Could implement true async initialization with asyncio instead of threading