fix: run execute_command_sync in thread pool to avoid event loop conflict (#468)

When async_processing=False, the sync path calls execute_command_sync()
which internally uses asyncio.run(). This fails when called from FastAPI's
already-running event loop with 'asyncio.run() cannot be called from a
running event loop'.

Wrapping the call in asyncio.to_thread() runs it in a thread pool executor,
avoiding the event loop conflict while preserving the synchronous behavior
from the API consumer's perspective.

Fixes #453
This commit is contained in:
Luis Novo 2026-01-24 18:19:02 -03:00 committed by GitHub
parent 28936d3944
commit f14020d385
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,3 +1,4 @@
import asyncio
import os
from pathlib import Path
from typing import Any, List, Optional
@ -449,11 +450,15 @@ async def create_source(
embed=source_data.embed,
)
result = execute_command_sync(
# Run in thread pool to avoid blocking the event loop
# execute_command_sync uses asyncio.run() internally which can't
# be called from an already-running event loop (FastAPI)
result = await asyncio.to_thread(
execute_command_sync,
"open_notebook", # app name
"process_source", # command name
command_input.model_dump(),
timeout=300, # 5 minute timeout for sync processing
300, # 5 minute timeout for sync processing
)
if not result.is_success():