设为首页 收藏本站
查看: 1222|回复: 0

[经验分享] System.Threading.Tasks.Task引起的IIS应用程序池崩溃

[复制链接]

尚未签到

发表于 2015-8-12 10:50:22 | 显示全部楼层 |阅读模式
  问题现象
  IIS应用程序池崩溃(Crash)的特征如下:
  1. 从客户端看,浏览器一直处于连接状态,Web服务器无响应。
  2. 从服务器端看(Windows Server 2008 + IIS 7.0),在事件日志中会出现Event ID为5010的错误:

  A process serving application pool 'q.iyunv.com' failed to respond to a ping. The process id was '20080'.

  这个错误的意思是:IIS检测到程序池'q.iyunv.com'无响应。为什么没有响应呢?因为程序池'q.iyunv.com'崩溃了。然后呢?IIS会强制回收应用程序池。
  (注:如果在你的Web服务器的事件日志中出现这个错误,一定是某个原因引起了应用程序池崩溃。)
  问题原因
  我们这次遇到的应用程序池崩溃,是由于在使用System.Threading.Tasks.Task进行异步操作时产生了未处理的异常。
  示例代码如下:



Task.Factory.StartNew(() =>
{
    //下面的代码未用try..catch捕获异常
    //...
});
  注:这是一个不需要Callback的异步操作,后续没有task.wait(或者静态方法Task.WaitAll或Task.WaitAny)操作。
  当时我们发布程序后,由于Task中代码产生了异常,整个站点无法正常访问,程序池一直处于“崩溃->回收->崩溃->回收”的循环。
  解决方法
  捕获Task中所有代码的异常,示例代码如下:



Task.Factory.StartNew(() =>
{
    try
    {
        //...
}
    catch { }
});
  问题分析
  在stackoverflow上提到了这个问题的原因:

  If you create a Task, and you don't ever call task.Wait() or try to retrieve the result of a Task<T>, when the task is collected by the garbage collector, it will tear down your application during finalization. For details, see MSDN's page on Exception Handling in the TPL.
  The best option here is to "handle" the exception.

  根据上面的英文,我的理解是:当你创建一个Task,没有调用过task.Wait()或者没有获取它的执行结果,(如果Task中出现了未处理的异常),当这个Task被GC回收时,在GC finalization阶段,会让当前应用程序崩溃。
  进一步看MSDN中的Exception Handling (Task Parallel Library):
  "Unhandled exceptions that are thrown by user code that is running inside a task are propagated back to the joining thread. ···Exceptions are propagated when you use one of the static or instance Task.Wait or Task(Of TResult).Wait methods···"
  翻译:在一个task中运行的代码抛出的未处理异常会被回传给(创建该task的)主线程。···当你调用Task.Wait时,异常才会被回传(给主线程)。
  分析:当我们遇到的情况是没调用Task.Wait,也就是异常没有被回传给主线程。下面的这句就提到了这个:
  "If you do not wait on a task that propagates an exception, or access its Exception property, the exception is escalated according to the .NET exception policy when the task is garbage-collected."
  译:如果你在一个task中没有等待异常被传播,或者访问它的异步特性,在task被GC回收时,该异常会遵循.NET异常策略被逐步升级。
  分析:逐步升级的后果就是当前应用程序进程崩溃,对于ASP.NET程序来说,就是应用程序池崩溃。
  进一步的解决方法
  MSDN上的推荐做法是用Task.ContinueWith观察Task中抛出的异常并进行处理,示例代码如下:



var task1 = Task.Factory.StartNew(() =>
{
    throw new MyCustomException("Task1 faulted.");
})
.ContinueWith((t) =>
    {
        Console.WriteLine("I have observed a {0}",
            t.Exception.InnerException.GetType().Name);
    },
    TaskContinuationOptions.OnlyOnFaulted);
  小结
  应用程序池崩溃的原因总结 —— System.Threading.Tasks.Task中的代码抛出了未处理的异常,由于没有Task.Wait()操作,异常没有被回传给主线程,在GC回收时,发现这个身份不明的异常。然后,这个异常被一级一级上报,直到当前程序进程的最高领导,最高领导为了顾全大局,果然决定与这个异常同归于尽,也就是让整个应用程序池崩溃。。。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-97844-1-1.html 上篇帖子: 在IIS中部署ASP.NET 5应用程序遭遇的问题 下篇帖子: IIS 500错误,一步帮你搞定.
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表