On Sep 4, 2014, at 5:00 PM, Lonnie Hutchinson <[email protected]> wrote:

> 
> 
> I am using sqlalchemy 0.8.5 with mysql 5.5 and think an intermittent failure 
> I am seeing may be due to an issue in sqlalchemy. Very infrequently I receive 
> an error from Session.add() stating the instance "is already attached to 
> session 'XXX' (this is 'YYY')" (see below for stack trace). I understand the 
> typical reason this error is raised, but I do not believe the instance should 
> still be attached to XXX, even though it was shortly before (milliseconds) 
> since Session.close() was called on the session.

OK I'm seeing some red flags here.  I see the word "intermittent", which almost 
always means, "multiple threads".  Then I see the word, "milliseconds".   Are 
we using threads?  Are we trying to time things?   Because looking at 0.8.5, 
when you call close(), the objects in that Session are absolutely de-assocaited 
with that Session, including that session_id is set to None.

This is very simple to confirm:

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class A(Base):
    __tablename__ = 'a'

    id = Column(Integer, primary_key=True)

e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)

sess = Session(e)
a1 = A()
sess.add(a1)
sess.commit()

assert a1._sa_instance_state.session_id == sess.hash_key
sess.close()
assert a1._sa_instance_state.session_id is None

there's no "milliseconds" here.  close() completes, and that id is gone.

If you are playing with threads, the only way to guarantee one thread finishes 
something before the other starts is to either join() that thread or use 
mutexes.


> My understanding of Session.close() is that upon return all instances should 
> be detached from the session and their instance state session_id attribute 
> should no longer reference the session. This does not appear to be happening 
> since adding the instance to a different session fails since the instance is 
> still attached to the previous session. 

Above I illustrate that this is not the case.   The code path is clear:

session.py -> line 942 -> close() calls:
session.py -> line 952 -> self.expunge_all()
session.py -> line 965 calls state._detach() on everything in identity + _new.  
 (question.  are you trying to move an object that was deleted?   that might 
have issues, but that's not a valid use case).
state.py -> line 166 -> _detach() calls:
state.py -> line 167:   self.session_id = self._strong_obj = None

> In reading the code it appears as though it is expected in certain situations 
> for the session_id to continue to refer to the session after close since the 
> check for already attached checks session_id as well as whether the session 
> remains in the sessions registry. 

I'm not seeing that in 0.8.5 at all.    what line of code are you referring to ?


-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to