0
votes

I'm working on an application that is multi-threaded and using NServiceBus and NHibernate with SQL Server 2008RC (using DTC). The process has one session factory. Each thread has it's own Session which is disposed of when the transaction is completed. We're intermittently seeing the exception below being thrown, it's happened 5 minutes after starting the process and 6 hours after starting the process. There doesn't seem to be a pattern for when it happens.

It looks like the AbstractBatcher is running into trouble closing commands when the DTC transaction is aborted.

Any help much appreciated.

Framework Version: v4.0.30319 Description: The process was terminated due to an unhandled exception. Exception Info: System.InvalidOperationException Stack: at System.Collections.Generic.Dictionary`2+KeyCollection+Enumerator[[System._Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System._Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].MoveNext() at NHibernate.AdoNet.AbstractBatcher.CloseCommands() at NHibernate.AdoNet.AbstractBatcher.Dispose(Boolean) at NHibernate.Impl.SessionImpl.Close() at NHibernate.Impl.SessionImpl.Dispose(Boolean) at NHibernate.Transaction.AdoNetWithDistributedTransactionFactory+<>c_DisplayClass1.b_0(System.Object, System.Transactions.TransactionEventArgs) at System.Transactions.TransactionCompletedEventHandler.Invoke(System.Object, System.Transactions.TransactionEventArgs) at System.Transactions.TransactionStatePromotedAborted.EnterState(System.Transactions.InternalTransaction) at System.Transactions.InternalTransaction.DistributedTransactionOutcome(System.Transactions.InternalTransaction, System.Transactions.TransactionStatus) at System.Transactions.Oletx.RealOletxTransaction.FireOutcome(System.Transactions.TransactionStatus) at System.Transactions.Oletx.OutcomeEnlistment.InvokeOutcomeFunction(System.Transactions.TransactionStatus) at System.Transactions.Oletx.OletxTransactionManager.ShimNotificationCallback(System.Object, Boolean) at System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(System.Object, Boolean)

1
Just curious - why can't you have a single session factory for the process and just open/close sessions per message?Udi Dahan
Sorry that is what we're doing, corrected the question above. The session is injected using the Scoped lifestyle from a Castle container, so we get a new one for every message.PBe
Any clues as to why the transaction is getting aborted?Adam Fyles

1 Answers

0
votes

It looks like this is due to some non thread-safe collection access in the AbstractBatcher. When the transaction is aborted the list of commands is iterated over. If another command is being run at the same time it will try to add the command to the list of commands. This causes the InvalidOperationException.

The issue has been logged in NHibernate JIRA and fixed in a pull request.