-1

I've .Net core C# application which calls a stored procedure with different parameters in parallel. From time to time I got the following exception.

The request failed to run because the batch is aborted, this can be caused by abort signal sent from client, or another request is running in the same session, which makes the session busy.

System.AggregateException: One or more errors occurred. (The request failed to run because the batch is aborted, this can be caused by abort signal sent from client, or another request is running in the same session, which makes the session busy.) ---> System.Data.SqlClient.SqlException: The request failed to run because the batch is aborted, this can be caused by abort signal sent from client, or another request is running in the same session, which makes the session busy.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.SqlInternalConnection.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.SqlDataReader.TryConsumeMetaData()
   at System.Data.SqlClient.SqlDataReader.get_MetaData()
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.CompleteAsyncExecuteReader()
   at System.Data.SqlClient.SqlCommand.InternalEndExecuteReader(IAsyncResult asyncResult, String endMethod)
   at System.Data.SqlClient.SqlCommand.EndExecuteReaderInternal(IAsyncResult asyncResult)
   at System.Data.SqlClient.SqlCommand.EndExecuteReader(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()

What caused the exception?

var options = new ParallelOptions { MaxDegreeOfParallelism = 4 };
Parallel.ForEach(items, options, t =>
{
    try
    {
        var result = DoWork(t.A, t.Range).Result;
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, $"{ex.ToString()}");
    }
});

public async Task<string> DoWork(A table, SqlXml range)
{
    _context.Database.SetCommandTimeout(150000);
    using (var cmd = Conn.CreateCommand())
    {
        cmd.CommandTimeout = 1200;
        cmd.CommandText = "storedProc";
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(new SqlParameter("@id", SqlDbType.SmallInt) { Value = table.Id });
        cmd.Parameters.Add(new SqlParameter("@Range", SqlDbType.Xml) { Value = range });
        var result = await cmd.ExecuteScalarAsync();
        return result as string;
    }
}
ca9163d9
  • 27,283
  • 64
  • 210
  • 413

1 Answers1

2

DbContext is not thread safe and the error specifically states

or another request is running in the same session, which makes the session busy

so I'm guessing the attempt to issue a concurrent command is causing the problem. Instantiate a DbContext per thread. View this answer for a Parallel.ForEach example on how to do just that.

Moho
  • 15,457
  • 1
  • 30
  • 31
  • Or just use straight ADO.NET – T.S. Sep 26 '17 at 15:16
  • How archaic! ;) – Moho Sep 26 '17 at 15:16
  • Yea! but fast! Just to init context is probably slower than execute entire parallel – T.S. Sep 26 '17 at 15:18
  • Maybe, but then why issue the commands concurrently in the first place? My assumption is the commands take significant time if parallelization is beneficial. If they don't take significant time, executing them serially would be my preferred option for simplicity's sake. – Moho Sep 26 '17 at 15:21
  • The Cmd may access the remote linked server and may take a couple of seconds to a couple of minutes depends on the parameters. – ca9163d9 Sep 26 '17 at 15:32