Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the recommended scoped_session usage pattern in a multithreaded sqlalchemy webapp?

I'm writing an application with python and sqlalchemy-0.7. It starts by initializing the sqlalchemy orm (using declarative) and then it starts a multithreaded web server - I'm currently using web.py for rapid prototyping but that could change in the future. I will also add other "threads" for scheduled jobs and so on, probably using other python threads.

From SA documentation I understand I have to use scoped_session() to get a thread-local session, so my web.py app should end up looking something like:

import web from myapp.model import Session  # scoped_session(sessionmaker(bind=engine)) from myapp.model import This, That, AndSoOn urls = blah... app  = web.application(urls, globals())  class index:     def GET(self):         s = Session()         # get stuff done         Session().remove()         return(stuff)  class foo:     def GET(self):         s = Session()         # get stuff done         Session().remove()         return(stuff) 

Is that the Right Way to handle the session?

As far as I understand, I should get a scoped_session at every method since it'll give me a thread local session that I could not obtain beforehand (like at the module level).

Also, I should call .remove() or .commit() or something like them at every method end, otherwise the session will still contain Persistent objects and I would not be able to query/access the same objects in other threads?

If that pattern is the correct one, it could probably be made better by writing it only once, maybe using a decorator? Such a decorator could get the session, invoke the method and then make sure to dispose the session properly. How would that pass the session to the decorated function?

like image 913
Luke404 Avatar asked Apr 04 '11 21:04

Luke404


People also ask

What is SQLAlchemy Scoped_session?

sqlalchemy. A scoped_session is constructed by calling it, passing it a factory which can create new Session objects. A factory is just something that produces a new object when called, and in the case of Session , the most common factory is the sessionmaker , introduced earlier in this section.

Is SQLAlchemy thread safe?

Every pool implementation in SQLAlchemy is thread safe, including the default QueuePool . This means that 2 threads requesting a connection simultaneously will checkout 2 different connections. By extension, an engine will also be thread-safe.

What is Session flush in SQLAlchemy?

session. flush() communicates a series of operations to the database (insert, update, delete). The database maintains them as pending operations in a transaction.

What does Session rollback () do?

Session. commit() means that the changes made to the objects in the Session so far will be persisted into the database while Session. rollback() means those changes will be discarded.


1 Answers

Yes, this is the right way.

Example:

The Flask microframework with Flask-sqlalchemy extension does what you described. It also does .remove() automatically at the end of each HTTP request ("view" functions), so the session is released by the current thread. Calling just .commit() is not sufficient, you should use .remove().

When not using Flask views, I usually use a "with" statement:

@contextmanager def get_db_session():     try:         yield session     finally:         session.remove()  with get_db_session() as session:     # do something with session 

You can create a similar decorator.

Scoped session creates a DBMS connection pool, so this approach will be faster than opening/closing session at each HTTP request. It also works nice with greenlets (gevent or eventlet).

like image 84
Alex Lokk Avatar answered Oct 17 '22 21:10

Alex Lokk