tezvyn:

Why synchronous DB libraries block async FastAPI endpoints and correct SQLAlchemy usage

AI-drafted, machine-checkedSource: fastapi.tiangolo.comintermediate
Why synchronous DB libraries block async FastAPI endpoints and correct SQLAlchemy usage

This tests event loop blocking: sync DB calls in async def halt all requests. Answer: sync drivers block the loop despite releasing the GIL; use asyncpg with SQLAlchemy create_async_engine and AsyncSession. Red flag: recommending run_in_executor as default.

WHAT THIS TESTS: Understanding of the asyncio event loop and the distinction between concurrency and parallelism in FastAPI. The interviewer wants to know if you recognize that synchronous I/O operations block the event loop thread even if the underlying C extension releases the GIL, which destroys the concurrency model that async endpoints rely on.

A GOOD ANSWER COVERS: First, explain that a standard synchronous library like psycopg2 issues blocking socket calls. In an async def endpoint, this blocks the entire event loop thread, so while that one request waits for the database, no other request can be processed by that worker. Second, note that releasing the GIL is not enough; the event loop needs an await point to switch tasks, which sync code never yields. Third, describe the correct SQLAlchemy stack: use an async driver such as asyncpg, create an engine with create_async_engine, use AsyncSession from sqlalchemy.ext.asyncio, and explicitly await every query with await session.execute(). Fourth, mention that dependency injection in FastAPI should provide the async session to endpoints so that the framework can manage the async context correctly.

COMMON WRONG ANSWERS: Claiming that psycopg2 is fine because it releases the GIL and Python can run other threads. This misses the single-threaded event loop model. Suggesting run_in_executor or a thread pool as the default or primary solution; while this can wrap sync code, it adds thread overhead and is not the idiomatic pattern for high-throughput async services. Proposing to use the standard synchronous SQLAlchemy engine and session inside an async endpoint without any thread isolation, which directly blocks the loop. Failing to mention the need for an async database driver entirely.

LIKELY FOLLOW-UPS: How would you handle database migrations with an async SQLAlchemy setup? What is the performance difference between asyncpg and psycopg2 in a real benchmark? How do you manage connection pooling with create_async_engine? What happens if you accidentally call a sync ORM method inside an AsyncSession? How would you test async database endpoints?

ONE CONCRETE EXAMPLE: Imagine an endpoint that runs SELECT sleep(1) using psycopg2 inside async def read_item. With ten simultaneous requests, each blocks the loop sequentially and total latency approaches ten seconds. Replacing this with asyncpg and await session.execute(text("SELECT pg_sleep(1)")) allows the event loop to interleave all ten queries, and with a connection pool they return in roughly one second total.

Source: fastapi.tiangolo.com

Read the original → fastapi.tiangolo.com

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.