diff --git a/src/Cli/dotnet/TransactionalAction.cs b/src/Cli/dotnet/TransactionalAction.cs index 087b983112a7..623a3b394d0e 100644 --- a/src/Cli/dotnet/TransactionalAction.cs +++ b/src/Cli/dotnet/TransactionalAction.cs @@ -2,7 +2,9 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Reflection; using System.Transactions; +using Microsoft.DotNet.Cli.Utils; namespace Microsoft.DotNet.Cli { @@ -65,19 +67,44 @@ public static T Run( // This automatically inherits any ambient transaction // If a transaction is inherited, completing this scope will be a no-op T result = default(T); - using (var scope = new TransactionScope( - TransactionScopeOption.Required, - TimeSpan.Zero)) + try { - Transaction.Current.EnlistVolatile( - new EnlistmentNotification(commit, rollback), - EnlistmentOptions.None); + using (var scope = CreateTransactionScope( + TimeSpan.FromDays(10))) + { + Transaction.Current.EnlistVolatile( + new EnlistmentNotification(commit, rollback), + EnlistmentOptions.None); + + result = action(); - result = action(); + scope.Complete(); + } - scope.Complete(); + return result; } - return result; + catch (TransactionAbortedException ex) + { + Reporter.Verbose.WriteLine(string.Format("TransactionAbortedException Message: {0}", ex.Message)); + Reporter.Verbose.WriteLine( + $"Inner Exception Message: {ex?.InnerException?.Message + "---" + ex?.InnerException}"); + throw; + } + } + + private static void SetTransactionManagerField(string fieldName, object value) + { + typeof(TransactionManager).GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Static) + .SetValue(null, value); + } + + // HACK: https://github.com/dotnet/sdk/issues/21101 + // we should replace TransactionScope later. + private static TransactionScope CreateTransactionScope(TimeSpan timeout) + { + SetTransactionManagerField("s_cachedMaxTimeout", true); + SetTransactionManagerField("s_maximumTimeout", timeout); + return new TransactionScope(TransactionScopeOption.Required, timeout); } public static void Run(