Interceptor fires AfterTransactionCompletion too many times with distributed transactions and user-supplied connections
Description
Environment
Attachments
- 04 Mar 2010, 04:07 AM
- 04 Mar 2010, 04:07 AM
- 04 Mar 2010, 04:07 AM
Activity
Oskar Berggren November 16, 2013 at 8:38 PM
Fixed in 0df5b9dcfad471b0c014848efdf0aba8ab6dfb2f.
Oskar Berggren November 16, 2013 at 7:11 PM
This only occurs when user-supplied connections are used.
The AdoNetWithDistributedTransactionFactory will, in response to the TransactionCompleted event set IsInActiveTransaction to false and then call session.AfterTransactionCompletion(wasSuccessful, null), which will notify the connection manager with AfterTransaction(), but since this is a user-supplied connection, the connection manager won't close it or disconnect from it.
The TransactionCompleted event handler will then proceed to call session.CloseSessionFromDistributedTransaction(), which will dispose the session, which will close the session, which will call Close() on the connection manager. If the connection is managed by NHibernate, it would have been released already by AfterTransaction(), and so the connection manager has nothing left to do. With a user supplied connection however, the connection manager will proceed to call its Disconnect() method, and that in turn will call session.AfterTransactionCompletion(false, null). Yes, this really calls back to the same method that the TransactionCompleted event handler had already called.
It's also noteworthy that the connection manager refuses to Disconnect() if we are inside an active transaction. If we call Close() it will try to dispose any active transaction. That won't work for a distributed transaction, and for a non-distributed transaction the transaction itself will take care to notify the session that the transaction has completed.
So my conclusion is that the ConnectionManager has neither the need nor the business to notify the session. Either the call is coming from the session, in which case it can notify itself, or the notification should come from the transaction handling code, as it already does.
Oskar Berggren November 16, 2013 at 6:55 PM
I think the suggestions from https://nhibernate.jira.com/browse/NH-2057#icft=NH-2057 are not needed, at least not anymore. There was different change made to resolve the similar NH-2420. The remaining (or true) problem in https://nhibernate.jira.com/browse/NH-2057#icft=NH-2057 is probably related to threading issues.
Christian Stenz March 4, 2010 at 5:48 AM
Oh, forgot to say, you need to apply the proposed patch to https://nhibernate.jira.com/browse/NH-2057#icft=NH-2057 to get the test case to run.
In AdoNetWithDistrubtedTransactionFactory, line 50-57:
// NH2057
session.TransactionContext = null;
if (transactionContext.ShouldCloseSessionOnDistributedTransactionCompleted)
{
session.CloseSessionFromDistributedTransaction();
}
// NH2057
//session.TransactionContext = null;
AfterTransactionCompletion is fired twice for each session opened in a distributed transaction.
See the attached unit test.
Whether it should fire once for each session or once for each transaction can be debated, i am not sure what the intention with interceptor is, but it should surely not fire twice.