On Thu, Sep 4, 2014 at 5:53 PM, Michael Bayer <mike...@zzzcomputing.com>
wrote:

>
> > The code I say appears to expect the session_id to remain on detached
> states in certain situations is that the check in Session._attach checks
> not only the session_id but that the referenced session still exists in
> _sessions:
> >         if state.session_id and \
> >                 state.session_id is not self.hash_key and \
> >                 state.session_id in _sessions:
> >             raise sa_exc.InvalidRequestError(
> >                 "Object '%s' is already attached to session '%s' "
> >                 "(this is '%s')" % (orm_util.state_str(state),
> >                                     state.session_id, self.hash_key))
> >
> > I am interested in this in the hopes that sheds light on the source of
> the intermittent failures.
>
> yeah that code is intended to detect when an object is added to a session
> that hasn't been removed from another.
>
>
So, is the intent of the 'state.session_id in _sessions" clause to handle
the situation where the session is collected while it contains instances?


> However, the implementation for session.close() has a direct trace that
> leads to the "session_id" set to None for all objects that are either in
> the identity map, or in the "_new" (pending) collection.  There's no
> ambiguity there.
>

I agree, it appears to be pretty clear. However,  on the application side I
have log messages indicating I successfully commit() and close() the
session before receiving an error saying an instance is still attached to
it:

2014-08-13 14:14:11 tuk1m1cm1 [debug] [DEBUG] db.py:57 - transaction 8710
started

2014-08-13 14:14:12 tuk1m1cm1 [debug] [DEBUG] db.py:143 - transaction 8710
committed

2014-08-13 14:14:12 tuk1m1cm1 [debug] [DEBUG] db.py:57 - transaction 8719
started

2014-08-13 14:14:13 tuk1m1cm1 [debug] [DEBUG] db.py:140 - transaction 8719
rolled back2014-08-13 14:14:13 tuk1m1cm1 [err] [ERROR] threadutils.py:98 -
Error executing asynchronous operation asynch-op <function execute at
0x5e54c08>(, {}) : Object '<Account at 0x5d49250>' is already attached to
session '8710' (this is '8719') at Traceback (most recent call last):...

"transaction" refers to a session, the integer is the session.hash_key.


> > In debugging this I have noticed that after the first session has been
> closed() and the initializer has returned the session remains in _sessions.
> However, if I call gc.collect() the session is removed, suggesting it just
> hasn't been fully cleaned up yet.
>
> that's not really accurate.  There's a collection of all the Sessions in
> the weak referencing map _sessions, and Python's GC may not in fact remove
> those sessions in a deterministic way.  But that has no bearing upon
> testing objects that have been removed from that session, and therefore
> have no session_id, if they belong to that session - their session_id has
> been cleared out.
>
>
I believe this is relevant because if the session were to be GC'ed the
"state.session_id in _sessions" would not evaluate to true and the attach
to the session I want would succeed.


>
> > Since it takes both the state referencing the session and the session
> still existing in _sessions, I can't help but wonder if this is a gc issue.
> Unfortunately it is not feasible to add gc.collect() calls in our
> production application as it introduces too much overhead.
>
> I will tell you how this *can* happen.  If you have a Session, and you put
> objects in it, then you *don't* close the session; the session just is
> dereferenced, and is garbage collected at some point by the above mentioned
> weak dictionary.   The objects within that session will *not* have anything
> done to their session_id in that case.   If a new session is started up,
> and it happens to take over the same in-memory ID as the one that was just
> GC'ed, it will have the same hash key, and will then exist within
> _sessions.  Then you move your objects to a third session; they will in
> fact have a session_id that is represented in _sessions, albeit against a
> different session than they started with, and you get the error.
>
> So if that's the case, then the issue here is the result of objects
> belonging to ad-hoc sessions that are not closed() explicitly, then those
> objects are shuttled along to another session, while busy thread mechanics
> in the background keep creating new sessions that occasionally use the same
> session identifier and produce this collision.
>
> There's ways to test for this, like assigning a unique counter to each
> Session within an event, like the begin() event, then using the
> before_attach event to verify that session_id is None, and if not, take a
> peek at that Session and its counter, compare it to something on the state.
>
>
I believe I have ruled this out with the "transaction XXX
started/committed" logging I added since I do not see hash keys being
reused.


>
>
>
> --
> 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 sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> Visit this group at http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to