below are some assertions you could add, if these rules don't work exactly right then you could trip into that error condition
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index 5a27140ac..64da5072a 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -2354,11 +2354,11 @@ class Session(_SessionClassMethods): % len_) # useful assertions: - # if not objects: - # assert not self.identity_map._modified - # else: - # assert self.identity_map._modified == \ - # self.identity_map._modified.difference(objects) + if not objects: + assert not self.identity_map._modified + else: + assert self.identity_map._modified == \ + self.identity_map._modified.difference(objects) self.dispatch.after_flush_postexec(self, flush_context) diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py index 70420ca50..132f1e37e 100644 --- a/lib/sqlalchemy/orm/state.py +++ b/lib/sqlalchemy/orm/state.py @@ -767,8 +767,13 @@ class InstanceState(interfaces.InspectionAttr): state.expired_attributes.difference_update(dict_) + if instance_dict and state in instance_dict._modified: + assert state.modified + if instance_dict and state.modified: instance_dict._modified.discard(state) + elif instance_dict: + assert state not in instance_dict._modified state.modified = state.expired = False state._strong_obj = None On Mon, Feb 26, 2018 at 3:06 PM, Mike Bayer <mike...@zzzcomputing.com> wrote: > if you can at least share the stack trace that should tell a lot > > On Mon, Feb 26, 2018 at 3:05 PM, Mike Bayer <mike...@zzzcomputing.com> wrote: >> On Mon, Feb 26, 2018 at 2:54 PM, Cecil Rock <cecil.r...@gmail.com> wrote: >>> Hi, >>> >>> I have a question about some ORM internal state tracking stuff. If this >>> isn't the right venue for this type of question my apologies. >>> >>> I've run into what looks like a race condition using the ORM during some our >>> production workloads. I am trying to figure out if our code has a bug or if >>> we are hitting a bug inside the ORM. We are occasionally getting a >>> FlushError with this message "Over 100 subsequent flushes have occurred >>> within session.commit() - is an after_flush() hook creating new objects?"( >>> we are not using any event hooks.) >>> >>> I've managed to track this down to what looks like the session.identity_map >>> has an InstanceState in its modified list (i.e. the session is dirty) but >>> the InstanceState is not in the sessions.identity_map._dict (i.e not in the >>> session?). The InstanceState is showing that it is attached to the session. >>> >>> e.g. the WeakInstanceDict looks like this for the session... >>> _dict = {} # is empty >>> _modified = ( TheModifiedInstanceState ) >>> >>> >>> This is a difficult bug to reproduce, but seems more likely to occur if we >>> hold the session open longer like so... >>> >>> my_model = MyModel.query.filter('...').first() >>> my_model.attr = 'something' >>> sleep(1) >>> session.commit() <-- flush error "occasionally" >>> >>> >>> I was hoping someone could confirm for me that this is "never a valid state" >>> for the identity map to be in. (Or if I'm super lucky someone will >>> recognize this as a known bug or something). >> >> try doing a gc.collect() there instead of a sleep since it looks >> related to the object being garbage collected. >> >> but no, that is never a valid state and I cannot imagine how you would >> get that error without using any flush hooks. that error was put in >> after observing very specifically end-user event hooks that would add >> more things to the dirty state within the scope of a flush. There is >> no way that can happen otherwise. >> >> >> >> >>> >>> Thanks for the help, >>> >>> Cecil >>> >>> -- >>> SQLAlchemy - >>> The Python SQL Toolkit and Object Relational Mapper >>> >>> http://www.sqlalchemy.org/ >>> >>> To post example code, please provide an MCVE: Minimal, Complete, and >>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full >>> description. >>> --- >>> 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 https://groups.google.com/group/sqlalchemy. >>> For more options, visit https://groups.google.com/d/optout. -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- 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 https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.