Fix Pydantic ORM mode blocking the event loop #888
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
🐛 Fix FastAPI serialization of Pydantic ORM mode blocking the event loop.
Description
In the current implementation, if a path operation function returns a DB object with relations, and it is then serialized by Pydantic in ORM mode using
response_model
, the serialization is done in the main loop. And Pydantic with ORM mode would go and use the getters to retrieve the relationships (as it should, this is not Pydantic's fault), but that's a potentially (and most probably) I/O blocking operation, while it reads from the DB.Test it
To test the problem, run this sample application with Uvicorn:
It simulates a (very long) blocking operation with a
time.sleep()
.Open several tabs at the same time with the docs UI and do 1 request to
/item
and the rest to/
.The request to
/item
will take 15 seconds to load (as it should). But the other requests will also take 15 seconds to load while they should be instantaneous. This is because they are all running in the same main loop.Fix it
Then apply this fix and try again.
/item
will take 15 seconds (as it should) but additional requests to/
will be instantaneous.How it works
Whenever a path operation function uses normal
def
instead ofasync def
, the model serialization is done in a threadpool.There are no checks to see if the model uses ORM mode or not, as it's possible that the top-level model doesn't use ORM mode but a deeply nested sub-model could be using ORM mode.