Created
November 4, 2020 05:42
-
-
Save cheenamalhotra/638338ccc4dc83a7b15381fbd261fd38 to your computer and use it in GitHub Desktop.
Test Transaction Leak - no repro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Data.Common; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using System.Data; | |
using Microsoft.Data.SqlClient; | |
namespace TestTransactionLeak | |
{ | |
public class SqlContext : IDisposable, IAsyncDisposable | |
{ | |
private readonly CancellationToken _cancellationToken; | |
private readonly string _connectionString; | |
private DbConnection _sqlConnection; | |
private DbTransaction _sqlTransaction; | |
public SqlContext(string connectionString, CancellationToken cancellationToken) | |
{ | |
_connectionString = connectionString; | |
_cancellationToken = cancellationToken; | |
} | |
public ValueTask DisposeAsync() | |
{ | |
try | |
{ | |
Dispose(); | |
return default; | |
} | |
catch (Exception exception) | |
{ | |
return new ValueTask(Task.FromException(exception)); | |
} | |
} | |
public void Dispose() | |
{ | |
_sqlTransaction?.Dispose(); | |
_sqlTransaction = null; | |
_sqlConnection?.Dispose(); | |
_sqlConnection = null; | |
} | |
public async Task<DbConnection> SqlConnection() => _sqlConnection ??= await CreateConnection(); | |
private async Task<DbTransaction> SqlTransaction(IsolationLevel isolationLevel = IsolationLevel.Unspecified) => | |
_sqlTransaction ??= await CreateTransaction(isolationLevel); | |
public Task<DbTransaction> SqlTransactionWithNoLock() => SqlTransaction(IsolationLevel.ReadUncommitted); | |
private async Task<SqlConnection> CreateConnection() | |
{ | |
var result = new SqlConnection(_connectionString); | |
await result.OpenAsync(_cancellationToken); | |
return result; | |
} | |
private async Task<DbTransaction> CreateTransaction(IsolationLevel isolationLevel) => | |
await (await SqlConnection()).BeginTransactionAsync( | |
isolationLevel, _cancellationToken); | |
} | |
public static class Program | |
{ | |
private static string s_connString = "<connection_string>"; | |
public static void Main() | |
{ | |
// Runs Managed SNI on Windows - enables same codebase that runs on linux. | |
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows", true); | |
RunTest().Wait(); | |
} | |
private async static Task RunTest() | |
{ | |
for (int i = 0; i < 5; i++) | |
{ | |
var cancellationToken = new CancellationToken(); | |
await using SqlContext context = CreateContext(cancellationToken); | |
await using DbConnection connection = await context.SqlConnection(); | |
await using DbTransaction transaction = await context.SqlTransactionWithNoLock(); | |
await RunTestAsync(connection, | |
"SELECT @@TRANCOUNT", | |
cancellationToken: cancellationToken, | |
transaction: transaction | |
); | |
} | |
} | |
private static async Task RunTestAsync(DbConnection connection, string commandText, CancellationToken cancellationToken, DbTransaction transaction) | |
{ | |
DbCommand command = connection.CreateCommand(); | |
command.Transaction = transaction; | |
command.CommandText = commandText; | |
await using DbDataReader reader = await command.ExecuteReaderAsync(cancellationToken); | |
while (await reader.ReadAsync()) | |
{ | |
Console.WriteLine((connection as SqlConnection).ServerProcessId + " : Open Transactions = " + reader.GetValue(0)); | |
} | |
} | |
private static SqlContext CreateContext(CancellationToken cancellationToken) => new SqlContext(s_connString, cancellationToken); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment