Just reminding myself (and potentially others) that this both a potential bug (reported as NH-4077 <https://nhibernate.jira.com/browse/NH-4077>) and our own fault (for doing wonky things in event listeners).
We use a IPostUpdateEventListener in combination with a session (with its default FlushMode.Auto) and a transaction, then (accidentally) trigger an auto-flush from the listener. This clears the currently iterated list and may cause the ArgumentOutOfRangeException. It does not happen when it is the last entity being processed (so highly dependant on the entities being saved/updated and the logic used in the listener). It does not happen when FlushMode is set to FlushMode.Commit (or potentially others; I didn't try them). It does not happen when the transaction is removed (but thats probably not an option in most cases). In addition to that, doing the same thing from a IPostInsertEventListener may cause duplicate inserts and thus primary key violations. Luckily we can work around this by using a different session; the original code was rather fragile and needed an overhaul anyways. On Monday, February 22, 2016 at 12:57:15 PM UTC+1, BhaaL wrote: > > I'm not quite sure if this is something inside NHibernate, or something > that my application does, so I'm posting this here first before creating a > ticket. > > I randomly (and rarely) get an ArgumentOutOfRangeException in > ActionQueue.ExecuteActions > <https://github.com/nhibernate/nhibernate-core/blob/master/src/NHibernate/Engine/ActionQueue.cs#L125> > > when committing an ITransaction (created by ISession.BeginTransaction) > inside a TransactionScope. > In particular, the local size is something like 3 or 4 (depending on > where I get the Exception and the number of entities affected), while > list.Count > is 0 when it happens. The loop iteration is mostly at the last index when > it does; I've never seen it happen with an index lower than size-1 before. > > Code looks pretty much like this: > > public void DoStuff(Action<ISession> workInTx) > { > using (var scope = new TransactionScope(TransactionScopeOption.Required > )) > { > using (var session = SessionFactory.CreateSession()) // calls > ISessionFactory.CreateSession > { > using (var tx = session.BeginTransaction()) > { > workInTx(session); > tx.Commit(); > } > session.Flush(); > } > scope.Complete(); > } > } > > (I noticed that Committing the transaction also flushes the Session, so > the session.Flush() there may not be necessary...) > > The given code sample is called from a single thread (there is no manual > multithreading going on, nor is there any async/await, Task.Run, > Parallel.ForEach > or whatever involved), although there are potentially multiple (distinct, > non-related) threads running which also use their own instances of > ISession. Sessions are not shared between threads, mostly because our own > code isn't particularly thread-safe either; but in part also because > Session-use is similar to the one illustrated above - using-Blocks inside > methods without anything fancy around them. > > If anyone has some hints on how to fix this on my end (and it is in fact > an issue of my code, not NHibernate), I apologize in advance for posting on > the dev list instead of the user list. > But if it is indeed a bug, I'll happily throw everything I've found so far > (which isn't much I'm afraid) at a but report. > > In case it matters, this is on NHibernate 4.0.2GA; which we cannot update > in the near term for compatibility reasons. But since the same lines of > code still appear on master, it's likely that the most recent versions > are also affected. > > Thanks for reading, > BhaaL > -- --- You received this message because you are subscribed to the Google Groups "nhibernate-development" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
