[CSHARP-3690] IClientSessionHandle.IsInTransaction remains true even if transaction has been aborted Created: 27/May/21  Updated: 27/Oct/23  Resolved: 02/Jun/21

Status: Closed
Project: C# Driver
Component/s: Error Handling, Transactions
Affects Version/s: 2.12.3
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Daniel Camarena Assignee: Dmitry Lukyanov (Inactive)
Resolution: Works as Designed Votes: 0
Labels: InTransaction, command, exception, failed, transactions
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

C#; .NET 5; VS 2019; Windows 10, xunit 2.4.1


Attachments: Zip Archive MongoDbTestWithOutBinaries.zip     Zip Archive MongoDbTest_Fixed.zip    

 Description   

IClientSessionHandle.IsInTransaction remains true on aborted transaction because of e.g. MongoWriteException. CommitTransaction excepts afterwards with the message: MongoDB.Driver.MongoCommandException : Command commitTransaction failed: Transaction 1 has been aborted..

I've attached a complete VS 2019 solution with xunit unit tests to reproduce the behavior. Unit test AbortTransactionOnMongoDbException and ZombieSessionHowEcsDoesItTest4 fail because IsInTransaction is true even after transaction was aborted and therefore CommitTransaction is called. 



 Comments   
Comment by Daniel Camarena [ 22/Jun/21 ]

I solved it like advised by Dmitry Lukyanov: DAL is checking for MongoServerException, calls AbortTransaction and throws the exception again. 

If someone is interested in my solution how to handle it divided into DAL and BL: 

MongoDbTest_Fixed.zip

 

Comment by Daniel Camarena [ 22/Jun/21 ]

Dear Dmitry Lukyanov

thank you again for your response. 

I think I have no other option than to accept your answer and do the workaround in my business logic. I still think that the session variable IsInTransaction in the driver should represent the status of a transaction - apparently in the server - the client has no transactions and therefore it's irrelevant if it thinks that there is an transaction active. But anyway, it seems that we are not on the same page regarding this issue. 

 

Thank you again for you effort, 
best regards, 
Daniel

Comment by Dmitry Lukyanov (Inactive) [ 21/Jun/21 ]

Hello daniel.camarena@azo.com , the behavior you're seeing is designed. IsInTransaction represents the status of a transaction on the client side.

Comment by Daniel Camarena [ 21/Jun/21 ]

Hi, 

 

as I'm new here, I don't know if anybody is reading comments on "closed" items. A short "another developer is reflecting it" or "we are still thinking about it" or "you were wrong, everything is fine like it is" would be great. 

 

Thanks, Daniel

Comment by Daniel Camarena [ 03/Jun/21 ]

Dear Dmitry Lukyanov

 

thank you for your investigation and the answer. 

The unit test is just an easy example to show the behavior I'd have excepted in another way. I know that the second insert fails and why it fails. For me the interesting thing in the unit test is, that the transaction was aborted on server side for some reason, but the session object on client side still indicates that the transaction is active, which is not true. I don't want to call AbortTransaction because of a server side exception. The decision was already made by the server - the transaction was already aborted. The code in the except path is just to convince the client driver to indicate the correct information (IsInTranaction=false) which should not be job of the business logic, but the driver itself. So, I'd agree if the lines you sent would be in the driver. When the driver notices that the server has aborted a transaction it should bring local variables in the same state to represent the real state of the object on the server. 

 

Thank you for the example, but in my real world program this is unfortunately not possible because several different classes are working on the same transaction without knowing of each other. So one central part is starting the transaction, everybody else is listening on events, modifying data if necessary and at the end the transaction is committed. Therefore, the example you showed is quite easy and the easiest way to use the session object avoiding the problem I have, unfortunately not an option in my case. 

 

Long story short: From my point of view the driver should keep the provided information up to date and not obligate the user to do this. In this particular case: When the driver notices that the server has ended the transaction, it should bring local variables to a correct state. 

 

Thank you once again for your time and effort investigating in this issue. 

 

Best regards, Daniel 

Comment by Dmitry Lukyanov (Inactive) [ 01/Jun/21 ]

Hello daniel.camarena@azo.com,
you have 2 failed tests:

  • AbortTransactionOnMongoDbException - this test fails because in your second inserting attempt, the server side session is aborted due to failure, but the client-side doesn't know about it, so you should explicitly call AbortTransaction on failure:

                session.StartTransaction();
                try
                {
                    var doc = new BsonDocument();
                    coll.InsertOne(session, doc);
                    coll.InsertOne(session, doc); // this step will fail because the doc with the same _id is already inserted
                }
                catch (Exception ex)
                {
                    session.AbortTransaction();
                    throw ex;
                }
                session.CommitTransaction();
    

    to mark client-session aborted. Then IsInTransaction will provide expected value.

  • ZombieSessionHowEcsDoesItTest4 - the same as above

so, the behavior you're seeing is expected.
Also, you may want using WithTransaction API that handles this work for you. See this example

Comment by Mikalai Mazurenka (Inactive) [ 28/May/21 ]

Hi daniel.camarena@azo.com

Thanks for reporting this issue!

We need some time to investigate it and will come back to you.

Comment by Daniel Camarena [ 27/May/21 ]

Description in documentation of IsInTransaction which is not met: http://mongodb.github.io/mongo-csharp-driver/2.12/reference/driver/crud/sessions_and_transactions/#isintransaction 

Due to MongoDbException an transaction is aborted and call of commit and rollback is no longer possible. Everything is fine from my point of view if IsInTransaction would indicate it correctly. 

Generated at Wed Feb 07 21:46:00 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.