On Jun 14, 2010, at 4:49 PM, Vinay Sajip wrote:
> On Jun 14, 3:14 pm, Michael Bayer <[email protected]> wrote:
>
>> My advice would be, assuming you cannot isolate the issue inside a small
>> test case, to trap the application at the point at which it appears to be
>> opening a "mystery" SessionTransaction, dropping into pdb, and checking
>> around why there's more than one Session in memory, as well as checking what
>> gc.collect() accomplishes here.
>
> Okay, I found the "phantom" transaction - it's being created in the
> session.remove() call in the cleanup of the previous request, in the
> following code in orm/session.py, in SessionTransaction.close():
>
> if not self.session.autocommit:
> self.session.begin()
>
> I hadn't expected the SessionTransaction.close() to create a brand new
> SessionTransaction, sorry I missed that. But this means that SQLA
> starting state is different for two consecutive, identical requests -
> the session.remove() for the first request leaves a state which causes
> a different path to be taken by SQLA on the second request. How do I
> completely clean up after each request so that the next identical
> request is processed in the same way?
the new SessionTransaction that occurs in close() does not request any
connection resources, and is discarded immediately along with the session that
is the subject of remove(). I don't see how it could be affected by any
previous requests. Each request should have a totally new Session object, with
a totally new SessionTransaction object. The old one is gone as soon as
remove() completes.
Here is an example. Everything, including SessionTransactions, checked out
connections, are gone after remove():
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.orm.session import *
from sqlalchemy.pool import _ConnectionFairy as ConnectionFairy, NullPool
import gc
engine = create_engine('sqlite://', poolclass=NullPool)
Session = scoped_session(sessionmaker(bind=engine))
for i in range(10):
Session()
print "do things with session !"
trans_objects = [c.__class__ for c in gc.get_objects()
if isinstance(c, (SessionTransaction, ConnectionFairy))]
# one SessionTransaction exists
assert len(trans_objects) == 1
# use a connection
Session.execute("select 1")
trans_objects = [c.__class__ for c in gc.get_objects()
if isinstance(c, (SessionTransaction, ConnectionFairy))]
# one SessionTransaction, one ConnectionFairy exists
assert len(trans_objects) == 2
Session.commit()
Session.remove()
# ensure unreachable objects cleaned up
gc.collect()
trans_objects = [c.__class__ for c in gc.get_objects()
if isinstance(c, (SessionTransaction, ConnectionFairy))]
# zero SessionTransactions, ConnectionFairy objects exist
assert len(trans_objects) == 0
output:
do things with session !
do things with session !
do things with session !
do things with session !
do things with session !
do things with session !
do things with session !
do things with session !
do things with session !
do things with session !
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/sqlalchemy?hl=en.