I am experiencing an issue with FastAPI where the application gets deadlocked when using an infinite loop in an async route. Here is a simplified version of my FastAPI application (fastapi_test.py):
from fastapi import FastAPI
import random
app = FastAPI()
@app.get("/hello")
async def hello():
return {"Hello": "World"}
# This route works normally and /hello route keeps working
@app.get("/normal")
def route_normal():
while True:
print({"route_normal": random.randint(0, 10)})
# This route causes a whole application deadlock
@app.get("/async")
async def route_async():
while True:
print({"route_async": random.randint(0, 10)})
# requirements
# pip install fastapi uvicorn[standard]
When I call the /normal route, the application keeps working normally. However, when I call the /async route, the application gets deadlocked, and no routes work anymore. I am running the application using the following command:
uvicorn fastapi_test:app --workers 1
I have observed that this issue occurs when using an infinite loop inside an async route. Is there a known limitation or recommended way to handle infinite loops in async routes to avoid deadlocks?
I also benchmarked async and normal /hello route and got ~50% better results for async version.
ab -n 100000 -c 1000 http://127.0.0.1:8000/hello
All this is really confusing for me.
python 3.10 fastapi==0.104.1
I appreciate any guidance or insights into resolving this issue. Thank you!
this async + the while True loop, is causing python to lock as its trying to process the loop and not being able to switch to the other interal process.
@app.get("/async")
async def route_async():
this can be fixed by using background tasks
from fastapi import BackgroundTasks
@app.get("/async")
async def route_async(background_tasks: BackgroundTasks):
def background_task():
while True:
print({"route_async": random.randint(0, 10)})
background_tasks.add_task(background_task)
return {"message": "Background task started"}
full code
from fastapi import FastAPI
from fastapi import BackgroundTasks
import random
app = FastAPI()
@app.get("/hello")
async def hello():
return {"Hello": "World"}
@app.get("/normal")
def route_normal():
while True:
print({"route_normal": random.randint(0, 10)})
@app.get("/async")
async def route_async(background_tasks: BackgroundTasks):
def background_task():
while True:
print({"route_async": random.randint(0, 10)})
background_tasks.add_task(background_task)
return {"message": "Background task started"}
allow your async function to sleep
import asyncio
from fastapi import FastAPI
import random
app = FastAPI()
@app.get("/hello")
async def hello():
return {"Hello": "World"}
@app.get("/normal")
def route_normal():
while True:
print({"route_normal": random.randint(0, 10)})
@app.get("/async")
async def route_async():
while True:
await asyncio.sleep(0) # do a sleep here so that the main thread can do its magic, at least once per loop, changing the sleep duration will allow the main thread to process other threads longer, please read up more on the specifics
print({"route_async": random.randint(0, 10)})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With