代码之家  ›  专栏  ›  技术社区  ›  Pasi Savolainen

BeginTransaction引发“超时已过期”,仅在特定位置,仅启用mars

  •  0
  • Pasi Savolainen  · 技术社区  · 6 年前

    设置:

    • DOTNET核心2.1
    • aspnet主机,所以我们主要是IServiceCollection
    • Docker,Linux映像 microsoft/dotnet:2.1-aspnetcore-runtime
    • 主机上的SQL Server,侦听 0.0.0.0:1433
    • 连接字符串: data source=tcp:host.docker.internal,1433;initial catalog=ServiceBus;user id=servicebus;password=<123>;application name=sbtest;MultipleActiveResultSets=True

    当我在main中有以下代码(并行位)时,那么实际的事务创建代码(本质上 https://github.com/rebus-org/Rebus.SqlServer/blob/master/Rebus.SqlServer/SqlServer/DbConnectionProvider.cs#L42 意志 爆炸,以下例外。

    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);
    }
    

    例外:

        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()
    
    • 如果我修改 Parallel 要运行0..2,它也将超时。
    • 如果我将连接字符串更改为不具有mars,它将不会超时
    • 在任何情况下,查询和 BEGIN TRANSACTION 在SQL Server事件探查器中可见,并且MSSQL日志中没有错误
    • 拒绝创建的连接字符串是“解决方法”使用的1:1
    • rebus是第一个使用SQL连接的,但也会对自己的队列/子表进行(成功)查询。

    我的猜测是Rebus可能对环境做了一些影响事务创建的事情,但是由于发生了很多事情,我无法确定是什么。有点猜测正在使用的TransactionScope,并不知何故与此有关。

    编辑: Transaction.Current 引发异常时为空,因此我怀疑 TransactionScope 不涉及

    1 回复  |  直到 6 年前
        1
  •  0
  •   mookid8000    6 年前

    我的猜测是Rebus可能对环境做了一些影响事务创建的事情,但是由于发生了很多事情,我无法确定是什么。有点猜测正在使用的TransactionScope,并不知何故与此有关。

    Rebus不使用 TransactionScope (*),所以不是这样。

    很抱歉,我不明白反驳是怎么回事。在您发布的代码中没有显示rebus位,在堆栈跟踪中也没有涉及到rebus的内容,因此有点不清楚这与rebus是如何连接的。


    (*)你 可以 将rebs的交易与 System.Transactions.Transaction.Current 包括 Rebus.TransactionScopes 打包并调用 scope.EnlistRebus() 扩展方法,但它看起来不像您正在做的任何事情。