查找具有未观察到的异常的任务的最佳策略

本文关键字:异常 任务 最佳 策略 观察 查找 | 更新日期: 2023-09-27 18:25:25

假设我有以下代码:

private static void Run()
{
    TaskScheduler.UnobservedTaskException += delegate { Console.WriteLine("Unobserved task exception!"); };
    try
    {
        RunAsync().Wait();
    }
    catch (Exception)
    {
    }
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
    Thread.Sleep(Timeout.InfiniteTimeSpan);
}
private static async Task RunAsync()
{
    var task1 = ThrowAsync();
    var task2 = ThrowAsync();
    await task1;
    await task2;
}
private static async Task ThrowAsync()
{
    throw new Exception("Test exception");
}

此代码输出Unobserved task exception!,因为未观察到task2中的异常。

我的问题是:有没有任何方法可以通过编程确定哪个任务有未观察到的异常?例如,我想获得一个调用任务或类似任务的方法的堆栈跟踪:

Unobserved exception: task2 in RunAsync()

遗憾的是,仅仅跟踪异常堆栈是不够的。上面的代码只是一个演示,在现实世界的应用程序中,我有时会遇到未观察到的任务异常,堆栈跟踪如下:

System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Web.HttpApplication.get_CurrentModuleContainer()
   at System.Web.HttpApplication.PipelineStepManager.ResumeSteps(Exception error)

查找具有未观察到的异常的任务的最佳策略

可以判断哪个Task实例的异常未被观察到。这将是第二个await 下的task2

await task1;
await task2;

因为第一个CCD_ 5"观察"CCD_。

然后,如果事件处理程序被修改为显示TaskScheduler.UnobservedTaskException提供的实际任务异常

    TaskScheduler.UnobservedTaskException += delegate(object o, UnobservedTaskExceptionEventArgs ea)
    {
        Console.WriteLine($"Unobserved task exception! {ea.Exception.ToString()}");
    };

然后可以通过观察异常的堆栈跟踪来跟踪任务代码的失败区域:

Unobserved task exception!
System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. (Test exception)
---> System.Exception: Test exception
   at ConsoleApp1.Program.ThrowAsync() in C:'Users'sergepavlov'Desktop'ConsoleApp1'ConsoleApp1'Program.cs:line 42
   --- End of inner exception stack trace ---
---> (Inner Exception #0) System.Exception: Test exception
   at ConsoleApp1.Program.ThrowAsync() in C:'Users'sergepavlov'Desktop'ConsoleApp1'ConsoleApp1'Program.cs:line 42
<--- 

希望这是有道理的。