0

For some reason FastAPI doesn't respond to any requests while a request is handled. I would expect FastAPI to be able to handle multiple requests at the same time. I would like to allow multiple calls at the same time as multiple users might be accessing the REST API.

Minimal Example: Asynchronous Processes

After starting the server: uvicorn minimal:app --reload, running the request_test run request_test and executing test(), I get as expected {'message': 'Done'}. However, when I execute it again within the 20 second frame of the first request, the request is not being processed until the sleep_async from the first call is finished.

Without asynchronous Processes

The same problem (that I describe below) exists even if I don't use asynchronous calls and wait directly within async def info. That doesn't make sense to me.

FastAPI: minimal

#!/usr/bin/env python3
from fastapi import FastAPI
from fastapi.responses import JSONResponse
import time
import asyncio

app = FastAPI()

@app.get("/test/info/")
async def info():
    async def sleep_async():
        time.sleep(20)
        print("Task completed!")
    asyncio.create_task(sleep_async())
    return JSONResponse(content={"message": "Done"})

Test: request_test

#!/usr/bin/env python3

import requests

def test():
    print("Before")
    response = requests.get(f"http://localhost:8000/test/info")
    print("After")
    response_data = response.json()
    print(response_data)
Natan
  • 728
  • 1
  • 7
  • 23
  • 1
    `async` does not mean parallel. It means "give up time for other things to run while I'm waiting for something" - if you never give up time, nothing else can run in the same time. You can make starlette/fastapi use threading instead by dropping the `async` part of your function definition. – MatsLindh Aug 16 '23 at 12:36
  • Yes, it does. I read that before, but was missing the information that async doesn't mean parallel. Thank you. – Natan Aug 16 '23 at 12:52

2 Answers2

1

You need to set the number of workers as shown in the uvicorn settings

--workers <int>
Mohamed ElKalioby
  • 1,908
  • 1
  • 12
  • 13
-1

It is because while you have indeed written an async function, the time.sleep() method called inside that is not asynchronous. Async functions shouldn't have methods that block the thread inside them. You can fix this by simply modifying the code to use asyncio.sleep() instead:

#!/usr/bin/env python3
from fastapi import FastAPI
from fastapi.responses import JSONResponse
import time
import asyncio

app = FastAPI()

@app.get("/test/info/")
async def info():
    async def sleep_async():
        await asyncio.sleep(20)
        print("Task completed!")
    asyncio.create_task(sleep_async())
    return JSONResponse(content={"message": "Done"})

As you can see below, the requests are getting processed concurrently; enter image description here

Operator
  • 109
  • 4
  • I am of course using a different time consuming program during that time instead of `sleep`. – Natan Aug 16 '23 at 12:45
  • In that case you should add the actual method you are using because it's not worthwhile to anyone otherwise. What I currently added makes sense in the scenario you've provided. – Operator Aug 16 '23 at 12:47