Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using fast-api non-async libraries #260

Closed
codingsett opened this issue May 25, 2019 · 6 comments
Closed

Using fast-api non-async libraries #260

codingsett opened this issue May 25, 2019 · 6 comments
Labels
question Question or problem question-migrate

Comments

@codingsett
Copy link

Description

Hello i was wondering if i make my api with fast api and add libraries which are non-async will it work the same or will i have issues. Example is a library that sends requests to an external api. I am new to async stuff. Any advice will be appreciated thanks.

@codingsett codingsett added the question Question or problem label May 25, 2019
@dmontagu
Copy link
Collaborator

dmontagu commented May 25, 2019

FastAPI should have no issues making use of non-async libraries. As long as you define your endpoints properly, you can still get the performance benefits of the async event loop as long as the non-async libraries are only blocking on IO. So yes, a (non-async) library that sends requests to an external API should integrate nicely with a FastAPI-based backend.

From the FastAPI docs (https://fastapi.tiangolo.com/async/):

When you declare a path operation function with normal def instead of async def, it is run in an external threadpool that is then awaited, instead of being called directly (as it would block the server).

In other words, you'll get all the performance benefits as long as any calls with blocking IO are put inside an endpoint defined with def (and not async def).

If you do have blocking IO being called in an endpoint defined with async def, the server thread will remain blocked while waiting for a response.


More concretely, imagine you wanted to have an endpoint that would ultimately use a synchronous search client to execute a search (something like elasticsearch_dsl comes to mind).
Then the following would be safe, as it would execute the function in a threadpool:

app = fastapi.FastAPI()

@app.get("/search")
def search(q: str):  # using def here and NOT async def is important
    return sync_search_client.search(query=q)

On the other hand, if you wrote

@app.get("/search")
async def search(q: str):  # async def at the start of this line is the problem
    return sync_search_client.search(query=q)

then FastAPI would end up calling that function on the main server thread, and would block.

Note that the same holds if you call sync_search_client.search from inside a different function that is itself called by the endpoint (no matter how deeply nested). So when you define an endpoint using async def, you should be confident that there are no blocking calls being made downstream of any of the functions the endpoint calls.

Based on this, one might be inclined to just put all endpoints inside of functions defined with def instead of async def just to be safe, but as also described in the FastAPI docs, there is a small performance penalty when you use the threadpool to execute the endpoint function. So when you know it is safe, you are better off using an async def to define your endpoint.

@codingsett
Copy link
Author

@dmontagu Thanks for the clearing things up for me!

@tiangolo
Copy link
Owner

Excellent answer @dmontagu ! Thanks for helping here.

Thanks @codingsett for reporting back and closing the issue.

@tedivm
Copy link

tedivm commented Oct 1, 2019

It might be worth adding this to the documentation somewhere- I've been using this library for months but had no idea about the differences in def versus async def for the view functions would impact performance. In fact I'm actually using one of the exact use cases (elasticsearch-dsl) mentioned here and am running off to do some updates :-D

@jin09
Copy link

jin09 commented Aug 22, 2020

@dmontagu @tiangolo what if we want to do a blocking call in an async function? asyncio provides us with a sweet option called run_in_executor which I am assuming FastAPI uses for all APIs defined with def to run them in a different threadpool executor. Do we any such workaround for FastAPI so that we can use blocking sync functions within async functions?

@tiangolo
Copy link
Owner

tiangolo commented Nov 5, 2022

Hey @jin09, I built Asyncer for that 🤓 https://asyncer.tiangolo.com/

Sorry for the long delay! 🙈 I wanted to personally address each issue/PR and they piled up through time, but now I'm checking each one in order.

@tiangolo tiangolo changed the title [QUESTION] Using fast-api non-async libraries Using fast-api non-async libraries Feb 24, 2023
@tiangolo tiangolo reopened this Feb 28, 2023
Repository owner locked and limited conversation to collaborators Feb 28, 2023
@tiangolo tiangolo converted this issue into discussion #8313 Feb 28, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
question Question or problem question-migrate
Projects
None yet
Development

No branches or pull requests

5 participants