MSDTC and Transaction errors.

Jan 10, 2011 at 2:42 PM

Hi,

After using Orchard for a while and writing some custom modules we started seeing some weird transaction related errors (in 0.5, 0.8 and 0.9).

We finally found out what was happening so I'd like to share this with you and try to save you the painful debugging hours.

The errors we were getting were:


Exception Details: System.Data.SqlClient.SqlException: Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
The statement has been terminated.

Source Error 

Line 41: 
Line 42:                 Logger.Debug("Final work for transaction being performed");
Line 43:                 _scope.Dispose();
Line 44:                 Logger.Debug("Transaction disposed");
Line 45:             }

Source File: C:\P\Dev\Prototypes\Orchard\Prototype 0.9\src\Orchard\Data\TransactionManager.cs    Line: 43


Exception Details: System.InvalidOperationException: Timeout expired.  The timeout period elapsed prior to obtaining a connection from the pool.  This may have occurred because all pooled connections were in use and max pool size was reached.

Source Error:

Line 137:                criteria = criteria.SetMaxResults(count);
Line 138:            }
Line 139:            return criteria
Line 140:                .List<ContentItemVersionRecord>()
Line 141:                .Select(x => ContentManager.Get(x.Id, VersionOptions.VersionRecord(x.Id)))

 Source File: C:\P\Dev\Prototypes\Orchard\Prototype 0.9\src\Orchard\ContentManagement\DefaultContentQuery.cs    Line: 139


Exception Details: System.Transactions.TransactionAbortedException: The transaction has aborted.

Source Error: 

Line 24:             if (_scope == null) {
Line 25:                 Logger.Debug("Creating transaction on Demand");
Line 26:                 _scope = new TransactionScope(TransactionScopeOption.Required);
Line 27:             }
Line 28:         }

Source File: C:\P\Dev\Prototypes\Orchard\Prototype 0.9\src\Orchard\Data\TransactionManager.cs    Line: 26


Exception Details: System.Transactions.TransactionException: The operation is not valid for the state of the transaction.

Source Error:

 

Line 73: 
Line 74:             Configuration config = GetConfiguration();
Line 75:             return config.BuildSessionFactory();
Line 76:         }
Line 77: 

Source File: C:\P\Dev\Prototypes\Orchard\Prototype 0.9\src\Orchard\Data\SessionFactoryHolder.cs    Line: 75


 

Exception Details: System.Data.SqlClient.SqlException: Distributed transaction completed. Either enlist this session in a new transaction or the NULL transaction.

Source Error:

 

Line 41: 
Line 42:                 Logger.Debug("Final work for transaction being performed");
Line 43:                 _scope.Dispose();
Line 44:                 Logger.Debug("Transaction disposed");
Line 45:             }

 

Source File: C:\P\Dev\Prototypes\Orchard\Prototype 0.9\src\Orchard\Data\TransactionManager.cs    Line: 43


 

All of these happened because we were storing a per request dependency (in this case IContentManager) inside a singleton dependency.

This totally messed up with the TransactionScope inside the TransactionManager.

Among other things most requests to the DB were elevated to MSDTC and Orchard’s performance dropped to painfully slow.

The same happened in this thread:  http://orchard.codeplex.com/Thread/View.aspx?ThreadId=234857 but the problem was not clear and the solution somewhat magical.

 

Bottom line is:

If you are getting any of those mysterious errors check if you are saving an object beyond its expected scope (e.g. saving an IDependency inside an ISingletonDependency).

 

Hope this helps!

 

Best Regards,

Patricio.