BeginTransaction throws 'Timeout expired', only in specific place, only with MARS enabled

0

Setup:

  • dotnet core 2.1
  • aspnet host, so we mostly IServiceCollection stuff up
  • docker, linux image microsoft/dotnet:2.1-aspnetcore-runtime
  • sql server on host, listening 0.0.0.0:1433
  • connection string : data source=tcp:host.docker.internal,1433;initial catalog=ServiceBus;user id=servicebus;password=<123>;application name=sbtest;MultipleActiveResultSets=True

When I have following code (the parallel bit) in Main, then the actual ReBus transaction creation code (essentially https://github.com/rebus-org/Rebus.SqlServer/blob/master/Rebus.SqlServer/SqlServer/DbConnectionProvider.cs#L42 ) will not blow up with exception below.

public static void Main(string[] args) {
  // will not timeout if this runs
  var res = Parallel.For(0, 8, (num) => {
    var cs = <connectionstring>;
    using (var c = new SqlConnection(cs)) {
      c.Open();          
      var t = c.BeginTransaction(IsolationLevel.ReadCommitted);
      // Dapper
      c.Query("select 2; waitfor delay '00:00:01'", transaction: t);
      t.Commit();
      t.Dispose();
      System.Console.WriteLine($"transtest {num} done");
  }});

  Main<Startup>(args);
}

Exception:

    System.Data.SqlClient.SqlException (0x80131904): Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding. ---> System.ComponentModel.Win32Exception (258): Unknown error 258
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(Byte[] buffer, TransactionManagerRequestType request, String transactionName, TransactionManagerIsolationLevel isoLevel, Int32 timeout, SqlInternalTransaction transaction, TdsParserStateObject stateObj, Boolean isDelegateControlRequest)
   at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransactionYukon(TransactionRequest transactionRequest, String transactionName, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest)
   at System.Data.SqlClient.SqlInternalConnection.BeginSqlTransaction(IsolationLevel iso, String transactionName, Boolean shouldReconnect)
   at System.Data.SqlClient.SqlConnection.BeginTransaction(IsolationLevel iso, String transactionName)
   at Company.Configuration.ServiceBus.ServiceBusConnectionProvider.<GetConnection>b__13_0()
  • If I modify Parallel to run 0..2, it will also timeout.
  • If I change connection string to not have MARS, it will not timeout
  • In all cases the queries and BEGIN TRANSACTION are visible in SQL Server Profiler and no errors are on MSSQL log
  • The connection string that ReBus ends up creating is 1:1 that the "workaround" uses
  • Rebus ends up being first that uses SQL connection, but also does (successfull) queries to it's own queues/subs tables

My guess is that ReBus might be doing something to environment which somehow affects the transaction creation, but as there is a lot happening, I can't pinpoint what. Kinda guessing on TransactionScope being used and somehow involved with this.

edit: Transaction.Current is null when exception is raised so I suspect TransactionScope is not involved

sql-server
.net-core
rebus
asked on Stack Overflow Oct 18, 2018 by Pasi Savolainen • edited Oct 19, 2018 by Pasi Savolainen

1 Answer

0

My guess is that ReBus might be doing something to environment which somehow affects the transaction creation, but as there is a lot happening, I can't pinpoint what. Kinda guessing on TransactionScope being used and somehow involved with this.

Rebus doesn't use TransactionScope(*), so that's not it.

I'm sorry, but I didn't understand where Rebus fit into this. There's no Rebus bits showing in the code you posted, and there's no Rebus things involved in the stack trace, so it's a little bit unclear how this is connected to Rebus.


(*) You can hook Rebus' transaction up with System.Transactions.Transaction.Current by including the Rebus.TransactionScopes package and calling the scope.EnlistRebus() extension method, but it doesn't seem like anything you're doing.

answered on Stack Overflow Oct 21, 2018 by mookid8000

User contributions licensed under CC BY-SA 3.0