TaskScheduler.UnobservedTaskException 与 TaskCompletionSource 中的异常处理
背景问题
监控发现 TaskScheduler.UnobservedTaskException 中上报的很多异常,业务明明是处理了的,但还是被捕获到了。
Task 中的异常
在 C# 中,写这样一段代码:
Task.Run(() =>
{
throw new InvalidOperationException("throw in task");
});
这里异常在 Task 里面没有被捕获,外面也没有 await Task 的执行结果,那么,这个异常就成了游离的状态。
如果订阅了 TaskScheduler.UnobservedTaskException 事件,TaskScheduler.UnobservedTaskException += TaskSchedulerOnUnobservedTaskException
在垃圾回收时,如果发现有 Task 中的异常没有被处理,则会在这个事件中暴露。
不订阅这个事件也不影响,从 .NET45 开始,这个异常不会导致进程意外终止。只是从业务上,会不知道发生了什么。
TaskCompletionSource 中的异常
如果使用了 TaskCompletionSource,使用了类似这样的代码,
var resultCompletionSource = new TaskCompletionSource<T>();
try
{
var result = await Runner.Do();
resultCompletionSource.SetResult(result);
return result;
}
catch (Exception ex)
{
resultCompletionSource.SetException(ex); // 给 TaskCompletionSource 设置异常
throw;
}
因为一些业务逻辑,最终 resultCompletionSource 没有被使用(被 await 拿结果),如果 resultCompletionSource 被设置了异常,则在垃圾回收 resultCompletionSource 时,也会触发 TaskScheduler.UnobservedTaskException
事件(如果订阅了)。
所以,需要找一个合适的时机,主动捕获 resultCompletionSource 中的异常。
try
{
if (resultCompletionSource.Task.IsFaulted)
{
await resultCompletionSource.Task;
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
背景问题原因
其实就是,虽然业务上处理了异常,但是有被“遗弃”的 TaskCompletionSource 中还有异常,最后垃圾回收时被 TaskScheduler.UnobservedTaskException
发现了。
原文地址:https://www.cnblogs.com/jasongrass/p/15129322.html
- ASP.NET MVC编程——错误处理与日记
- Jenkins 未授权远程代码执行漏洞(CVE-2017-1000353)
- ASP.NET MVC编程——路由
- ASP.NET MVC编程——模型
- ASP.NET MVC编程——验证、授权与安全
- 如何使用SAML配置CDSW的身份验证
- ASP.NET MVC编程——控制器
- ASP.NET MVC编程——视图
- 设计原则
- Entity Framework——配置文件设置
- 如何安装SAS并配置连接Hive/Impala
- Entity Framework——记录执行的命令信息
- 【BlackHat 2017 议题剖析】连接的力量:GitHub 企业版漏洞攻击链构造之旅
- CVE-2015-1641 Word 利用样本分析
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 精讲RestTemplate第8篇-请求失败自动重试机制
- 精讲RestTemplate第7篇-自定义请求失败异常处理
- 精讲RestTemplate第10篇-使用代理作为跳板发送请求
- 精讲响应式WebClient第5篇-请求超时设置与异常处理
- 精讲响应式WebClient第4篇-文件上传与下载
- 【大家的项目】Rust Base62 库学习和分析
- ES2020 中 Javascript 10 个你应该知道的新功能
- Webpack5 跨应用代码共享 - Module Federation
- 【Rust日报】2020-09-16 - Rust 2021 规划
- 精讲响应式WebClient第3篇-POST、DELETE、PUT方法使用
- C++的黑魔法: 用四种方式实现add!
- 精讲响应式WebClient第2篇-GET请求阻塞与非阻塞调用方法详解
- 算法篇:位运算异或的使用(一)
- 精讲响应式webclient第1篇-响应式非阻塞IO与基础用法
- k8s 二进制集群平滑升级 1.15.2升级至1.16.4