Fix Pydantic ORM mode blocking the event loop#888
Merged
Conversation
Codecov Report
@@ Coverage Diff @@
## master #888 +/- ##
=====================================
Coverage 100% 100%
=====================================
Files 292 292
Lines 7663 7665 +2
=====================================
+ Hits 7663 7665 +2
Continue to review full report at Codecov.
|
12 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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
/itemand the rest to/.The request to
/itemwill 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.
/itemwill take 15 seconds (as it should) but additional requests to/will be instantaneous.How it works
Whenever a path operation function uses normal
definstead 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.