Comments (12)
Excellent, thanks! And thanks a lot for the really fast turn-around! You rock!!
from fastapi.
@euri10 as always, thanks for the help here!
@alexiri I'm creating a full-stack-fasapi-postgresql project generator and I'm being able to reproduce the issue.
The abstract steps to solve it are:
- Don't use a
scoped_session
but a standardSession
. - Create a session per-request.
- Close the session after the request is done.
To finish implementing it in FastAPI in the simplest and more convenient way, we depend on a feature of Starlette that will be available soon: encode/starlette#379
Meanwhile, a "hack" to work around it, that is the closest to what we want is described in the updated docs: https://fastapi.tiangolo.com/tutorial/sql-databases/
In short, the situation happens because FastAPI will call the non-async functions in a separate thread, and the scoped_session
will create a separate session for each sub-thread, but then it is not being closed properly.
If you don't want to use the technique described in the docs, you can just create a new Session
with db_session = Session()
at the beginning of each path operation function and call db_session.close()
at the end (as you are doing).
For more information, check the comments here: encode/starlette#370 (comment)
This is just an update on the state of it, so you know how to proceed meanwhile, but once we have request.state
I'll update the docs accordingly.
from fastapi.
So, request.state
in Starlette was implemented today: encode/starlette#404
I just updated FastAPI to upgrade the Starlette version (and the compatibility changes).
And I updated the tutorial for SQL with SQLAlchemy using the new request.state
: https://fastapi.tiangolo.com/tutorial/sql-databases/
You should now be able to use the new, proper technique, with FastAPI version 0.6.0
π
from fastapi.
The documentation/tutorial for SQLAlchemy was broken, sorry for that π₯
It is fixed now, and the code of the tutorial itself is now part of the tests, so it is now continuously ensured that that code works as it should.
The new tutorial doesn't require a full PostgreSQL server, as it uses a SQLite database (a single file), so, you should be able to just copy the code as is, and run it locally, and there you would have a full FastAPI (micro) application, serving from a local database (in a file tests.db
).
Please try the new tutorial an let me know how it goes: https://fastapi.tiangolo.com/tutorial/sql-databases/
from fastapi.
from fastapi.
Hola @tiangolo, thanks a lot for this great update, I understand the problem now. I've implemented the hack for now until the final solution is available.
from fastapi.
Hola @tiangolo,
I must still be doing something wrong, I'm still exhausting the connection pool.
My app.models __init__.py looks like this:
...
engine = create_engine(DATABASE_URI,
convert_unicode=True,
echo=False, echo_pool=True,
pool_size=5,
max_overflow=0,
pool_recycle=1)
db_session = scoped_session(
sessionmaker(autocommit=False, autoflush=False, bind=engine)
)
class CustomBase:
# Generate __tablename__ automatically
@declared_attr
def __tablename__(cls):
return cls.__name__.lower()
Base = declarative_base(cls=CustomBase)
Base.metadata.create_all(bind=engine)
Then, from each place I need a DB connection (like app.crud.user) I do a
from app.models import db_session
...
def get_user_by_id(userid):
return db_session.query(User).get(userid)
I guess this isn't the right way of doing it, as it seems each import opens a new connection and it never gets released. What should I be doing instead?
from fastapi.
I'm using Postgres and the error I get is:
sqlalchemy.exc.TimeoutError: QueuePool limit of size 5 overflow 0 reached, connection timed out, timeout 30 (Background on this error at: http://sqlalche.me/e/3o7r)
This happens after 5 queries to the DB, which leads me to believe I'm not liberating connections as I should.
Still, you're right, the easiest way forward is for me to produce a test case. I'll work on that when I have some time.
from fastapi.
You might want to take a look at this explanation
I also wrote a sample test case with a postgresql db and several engine configs, looping from 6 to 100 times the same route, facing no timeouts, hope it helps
notice that without https://github.com/euri10/fastapi/blob/58628e81efe027afb2e9ec5ae19113f13a35a7a1/tests/test_psql_pool.py#L51 the timeout will occur as expected when the max_overflow + current connections is reached, hence the read above that explains all that better than I could :)
from fastapi.
I was just putting this together to show the issue I'm having: https://github.com/alexiri/fastapi_hang. I see now that the problem seems to be how I'm using dependencies that also query the database. The reason I'm trying to do that is to create dependencies that verify a user's role to see if they're allowed to perform a particular action, imitating get_current_user
in the Security examples.
The issue does go away if I put a db_session.close()
after both queries, but then I guess one request opens and closes two DB sessions... I guess I'm going about this all wrong?
from fastapi.
Thanks! π
from fastapi.
Assuming the original need was handled, this will be automatically closed now. But feel free to add more comments or create new issues or PRs.
from fastapi.
Related Issues (20)
- No streaming interface can not support concurrency for two fastapi servers
- Using pydantic Json Type as Form data type doesn't work HOT 1
- Raw docstring (leading `r`) defeats form feed `\f` truncation HOT 3
- OpenAPI Example with multipart/form-data not showing up HOT 5
- [BUG] Using Nested Pydantic models and `params: MyModel = Depends()` forces OpenAPI docs GET methods to require a request body. HOT 6
- How to fix this bug? HOT 2
- [BUG] Upgrade python-mulipart==0.0.7 from low version fastapi upload file may be 400 HOT 4
- Use `RootModel` as query parameter HOT 2
- Context managers in `Depends` are broken after 0.106 HOT 17
- Middleware runs twice HOT 8
- Support for Pydantic deprecated fields HOT 1
- axios can't receive error response status code
- Potential footgun when using custom `Response(background=<Task()>)` in conjunction with injected `BackgroundTasks` - the custom response overwrites the tasks HOT 3
- lifespan
- Breaking change with path parameters when updating to pydantic>=2 from pydantic<2 HOT 1
- trying to live video stream using Fastapi
- Package on test.pypi.org is broken
- middleware type
- It throws an exception when I specify return Http status code
- When backend restart the frontend request a protected api cause an unhandle exception: Exception in ASGI application HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fastapi.