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.

Reply via email to