首页 > 解决方案 > 可以捕获并重试内部 clr 异常吗?

问题描述

在调用 .ToArray 时,我遇到了以下异常:

Internal CLR error. (0x80131506)
at System.Linq.Enumerable.ToArray[[System.__Canon, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](System.Collections.Generic.IEnumerable`1<System.__Canon>)

这种情况是间歇性发生的,并且很难重现。这种类型的异常可以被捕获并重试吗?我是否只需要捕获一个通用异常。

调用 .ToArray() 的代码位于异步任务中。在异步代码之外已经有一个通用的 try/catch 来捕获任何异常并记录它。它似乎没有到达该代码(正如未打印日志消息的事实所证明的那样)

不幸的是,我没有一个很好的可重现的小例子。如果我有一个,我可能可以调试并找出问题所在。它可能发生在 1% 的时间里。

通用结构如下所示:

private async Task<bool> Foo()
{
    try
    {
      return (await Bar()).Value;
    }
    catch (Exception e)
    {
       LogError();
       return false;
    }
}

private async Task<bool> Bar()
{
    // workQueue uses an ActionBlock to run tasks
    var tasks = workToDo.Select(item => await workQueue.ProcessItem(item, DoWorkOnItem));
    await Task.WhenAll(tasks);
}

async Task<bool> DoWorkOnItem(Item i)
{
    var convertedStatements = i.Select(s => ConvertStatement(s, context)).Where(s => s != null).ToList();
    var statementArray = ConvertedStatement.FlattenStatements(convertedStatements).ToArray(); // This is where the exception is hit
}

public static IList<Statement> FlattenStatements(ICollection<ConvertedStatement> convertedStatements)
{
    Contract.Requires(convertedStatements != null);

     var result = new List<Statement>(convertedStatements.Count);
     foreach (var statement in convertedStatements)
     {
         // m_statement is only set in the constructor of Statement
         if (statement.m_statement != null)
         {
             result.Add(statement.m_statement);
         }
         else
         {
             // m_statements is a read-only list of Statement, only set in the constructor of Statement
             result.AddRange(statement.m_statements);
         }
     }

     return result;
}

我应该在排队的任务中添加一个 try catch 吗?当它打印内部 CLR 错误的完整异常时,该跟踪不包括 Foo(),它会像这样抛出动作块:

 at BuildXL.FrontEnd.Sdk.SourceFileProcessingQueue`1[[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].ProcessWorkItem(QueueInput`1<Boolean,Boolean>)
 at System.Threading.Tasks.Dataflow.ActionBlock`1[[BuildXL.FrontEnd.Sdk.SourceFileProcessingQueue`1+QueueInput`1[[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], BuildXL.FrontEnd.Sdk, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6212d9137135ce5d]].ProcessMessageWithTask(System.Func`2<QueueInput`1<Boolean,Boolean>,System.Threading.Tasks.Task>, System.Collections.Generic.KeyValuePair`2<QueueInput`1<Boolean,Boolean>,Int64>)
 at System.Threading.Tasks.Dataflow.ActionBlock`1+<>c__DisplayClass6_1[[BuildXL.FrontEnd.Sdk.SourceFileProcessingQueue`1+QueueInput`1[[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], BuildXL.FrontEnd.Sdk, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6212d9137135ce5d]].<.ctor>b__2(System.Collections.Generic.KeyValuePair`2<QueueInput`1<Boolean,Boolean>,Int64>)
 at System.Threading.Tasks.Dataflow.Internal.TargetCore`1[[BuildXL.FrontEnd.Sdk.SourceFileProcessingQueue`1+QueueInput`1[[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], BuildXL.FrontEnd.Sdk, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6212d9137135ce5d]].ProcessMessagesLoopCore()
 at System.Threading.Tasks.Task.InnerInvoke()
 at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(System.Threading.Thread, System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
 at System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread)
 at System.Threading.ThreadPoolWorkQueue.Dispatch()

这让我认为 try catch 应该在 DoWorkOnItem 中,而不是 Foo 中。听起来对吗?

标签: c#exception.net-core

解决方案


这看起来像是一个合法的内部错误。如果您搜索错误代码,您会发现出现这种情况的实例,然后是 Microsoft 的修复程序。

可以捕获并重试内部 clr 异常吗?

我很好奇,你试过吗?你的结果是什么?

这不是FileNotFoundException,您可能正确地认为您可以重试。这是有问题的,因为您不知道 CLR/执行引擎的内部状态可能被损坏到何种程度。重试可能会给您带来另一个异常,或者仅仅是不正确的结果。

简而言之,如果您使用的是最新版本,那么正确的做法可能是向 Microsoft 报告。


推荐阅读