The /analyze endpoint in main.py is declared async, which means FastAPI runs it on the event loop. However, it calls analyze_logs(temp_path, numeric_threshold) which is a fully synchronous, CPU-bound function in logic.py — it opens a file, reads every line, runs regex on each line, and builds a list of incidents, all in a blocking loop.
When a large log file is submitted (up to 50 MB is allowed), this synchronous call can block the event loop for several seconds. During that time, FastAPI cannot process any other incoming requests — including health checks, login requests from other users, or concurrent analysis requests. This effectively makes the server single-threaded under load.
The correct fix is to run analyze_logs in a thread pool using asyncio.to_thread() (Python 3.9+) or loop.run_in_executor(), which offloads the blocking work to a worker thread and keeps the event loop free. This is a standard FastAPI pattern for CPU-bound or I/O-bound synchronous functions.
The
/analyzeendpoint in main.py is declared async, which means FastAPI runs it on the event loop. However, it callsanalyze_logs(temp_path, numeric_threshold)which is a fully synchronous, CPU-bound function inlogic.py— it opens a file, reads every line, runs regex on each line, and builds a list of incidents, all in a blocking loop.When a large log file is submitted (up to 50 MB is allowed), this synchronous call can block the event loop for several seconds. During that time, FastAPI cannot process any other incoming requests — including health checks, login requests from other users, or concurrent analysis requests. This effectively makes the server single-threaded under load.
The correct fix is to run
analyze_logsin a thread pool usingasyncio.to_thread()(Python 3.9+) orloop.run_in_executor(), which offloads the blocking work to a worker thread and keeps the event loop free. This is a standard FastAPI pattern for CPU-bound or I/O-bound synchronous functions.