定时Job在IIS中潜在危险-IIS 定期回收
引言
有时我们会在IIS中启用一些定时服务,但是你必须清楚IIS会定期回收Asp.net的应用程序的。首先来看IIS啥时候回收APPDomain.
APPDomain 回收时机
There are several things that can cause ASP.NET to tear down your AppDomain.
- When you modify web.config, ASP.NET will recycle the AppDomain, though the w3wp.exe process (the IIS web server process) stays alive.
- IIS will itself recycle the entire w3wp.exe process every 29 hours. It’ll just outright put a cap in the w3wp.exe process and bring down all of the app domains with it.
- In a shared hosting environment, many web servers are configured to tear down the application pools after some period of inactivity. For example, if there are no requests to the application within a 20 minute period, it may take down the app domain.
If any of these happen in the middle of your code execution, your application/data could be left in a pretty bad state as it’s shut down without warning.
So why isn’t this a problem for your typical per request ASP.NET code?
When ASP.NET tears down the AppDomain, it will attempt to flush the existing requests and give them time to complete before it takes down the App Domain. ASP.NET and IIS are considerate to code that they know is running,such as code that runs as part of a request.
Problem is, ASP.NET doesn’t know about work done on a background thread spawned using a timer or similar mechanism. It only knows about work associated with a request.
有哪些风险
There are three main risks, one of which I’ll focus on in this blog post.
- An unhandled exception in a thread not associated with a request will take down the process. This occurs even if you have a handler setup via the Application_Error method. I’ll try and explain why in a follow-up blog post, but this is easy to deal with.
- If you run your site in a Web Farm, you could end up with multiple instances of your app that all attempt to run the same task at the same time. A little more challenging to deal with than the first item, but still not too hard. One typical approach is to use a resource common to all the servers, such as the database, as a synchronization mechanism to coordinate tasks.
- The AppDomain your site runs in can go down for a number of reasons and take down your background task with it. This could corrupt data if it happens in the middle of your code execution.
告诉ASP.NET ,我还在运行
The good news is there’s an easy way to tell ASP.NET about the work you’re doing! In the System.Web.Hosting namespace, there’s an important class,HostingEnvironment. According to the MSDN docs, this class…
Provides application-management functions and application services to a managed application within its application domain
This class has an important static method, RegisterObject. The MSDN description here isn’t super helpful.
Places an object in the list of registered objects for the application.
For us, what this means is that the RegisterObject method tells ASP.NET that, “Hey! Pay attention to this code here!” Important! This method requires full trust!
This method takes in a single object that implements the IRegisteredObjectinterface. That interface has a single method:
public interface IRegisteredObject
{
void Stop(bool immediate);
}
When ASP.NET tears down the AppDomain, it will first attempt to call Stopmethod on all registered objects.
In most cases, it’ll call this method twice, once with immediate set to false. This gives your code a bit of time to finish what it is doing. ASP.NET gives all instances of IRegisteredObject a total of 30 seconds to complete their work, not 30 seconds each. After that time span, if there are any registered objects left, it will call them again with immediate set to true. This lets you know it means business and you really need to finish up pronto! I modeled my parenting technique after this method when trying to get my kids ready for school.
When ASP.NET calls into this method, your code needs to prevent this method from returning until your work is done. Levi showed me one easy way to do this by simply using a lock. Once the work is done, the code needs to unregister the object.
For example, here’s a simple generic implementation of IRegisteredObject. In this implementation, I simply ignored the immediate flag and try to prevent the method from returning until the work is done. The intent here is I won’t pass in any work that’ll take too long. Hopefully.
public class JobHost : IRegisteredObject
{
private readonly object _lock = new object();
private bool _shuttingDown; public JobHost()
{
HostingEnvironment.RegisterObject(this);
} public void Stop(bool immediate)
{
lock (_lock)
{
_shuttingDown = true;
}
HostingEnvironment.UnregisterObject(this);
} public void DoWork(Action work)
{
lock (_lock)
{
if (_shuttingDown)
{
return;
}
work();
}
}
}
I wanted to get the simplest thing possible working. Note, that when ASP.NET is about to shut down the AppDomain, it will attempt to call the Stop method. That method will try to acquire a lock on the _lock instance. The DoWork method also acquires that same lock. That way, when the DoWork method is doing the work you give it (passed in as a lambda) the Stop method has to wait until the work is done before it can acquire the lock. Nifty.
Later on, I plan to make this more sophisticated by taking advantage of using aTask to represent the work rather than an Action. This would allow me to take advantage of task cancellation instead of the brute force approach with locks.
With this class in place, you can create a timer on Application_Start (I generally use WebActivator to register code that runs on app start) and when it elapses, you call into the DoWork method here. Remember, the timer must be referenced or it could be garbage collected.
Here’s a small example of this:
using System;
using System.Threading;
using WebBackgrounder; [assembly: WebActivator.PreApplicationStartMethod(
typeof(SampleAspNetTimer), "Start")] public static class SampleAspNetTimer
{
private static readonly Timer _timer = new Timer(OnTimerElapsed);
private static readonly JobHost _jobHost = new JobHost(); public static void Start()
{
_timer.Change(TimeSpan.Zero, TimeSpan.FromMilliseconds(1000));
} private static void OnTimerElapsed(object sender)
{
_jobHost.DoWork(() => { /* What is it that you do around here */ });
}
}
建议
This technique can make your background tasks within ASP.NET much more robust. There’s still a chance of problems occurring though. Sometimes, the AppDomain goes down in a more abrupt manner. For example, you might have a blue screen, someone might trip on the plug, or a hard-drive might fail. These catastrophic failures can take down your app in such a way that leaves data in a bad state. But hopefully, these situations occur much less frequently than an AppDomain shutdown.
Many of you might be scratching your head thinking it seems weird to use a web server to perform recurring background tasks. That’s not really what a web server is for. You’re absolutely right. My recommendation is to do one of the following instead:
- Write a simple console app and schedule it using Windows task schedule.
- Write a Windows Service to manage your recurring tasks.
- Use an Azure worker or something similar.
Given that those are my recommendations, why am I still working on a system for scheduling recurring tasks within ASP.NET that handles web farms and AppDomain shutdowns I call WebBackgrounder (NuGet package coming later)?
I mean, besides the fact that I’m thick-headed? Well, for two reasons.
The first is to make development easier. When you get latest from our source code, I just want everything to work. I don’t want you to have to set up a scheduled task, or an Azure worker, or a Windows server on your development box. A development environment can tolerate the issues I described.
The second reason is for simplicity. If you’re ok with the limitations I mentioned, this approach has one less moving part to worry about when setting up a website. There’s no need to configure an external recurring task. It just works.
But mostly, it’s because I like to live life on the edge.
参考
The Dangers of Implementing Recurring Background Tasks In ASP.NET
https://github.com/NuGet/WebBackgrounder
Use IIS Application Initialization for keeping ASP.NET Apps alive
定时Job在IIS中潜在危险-IIS 定期回收的更多相关文章
- 在IIS中实现JSP
在IIS中实现JSP IIS本身是不可以支持JSP页面的,但是随着JAVA技术的广泛应用,越来越多的网站采用JAVA技术编写程序,我们根据一些资料和自己的实践经验总结了以下两种JAVA应用服务器 ...
- Quartz.net 定时任务在IIS中未按时执行
IIS 垃圾回收机制下解决Quartz.net 的不执行问题 IIS中涉及了垃圾回收机制,quartz.net 在ASP.NET 项目中可以实现线程监控定时执行任务,但是在IIS7.5机一下版本中涉及 ...
- Quartz.net 定时任务在IIS中没有定时执行
问题:Quartz.net 定时任务在项目部署到IIS中发现没有定时执行 解决方案: 1.在服务器上装一个360(自带自动刷新功能),在工具——>自动刷新——>自动刷新勾上 然后再设置一下 ...
- 从客户端中检测到有潜在危险的Request.Form值的解决办法
http://www.pageadmin.net/article/20141016/935.html 如果你网站iis服务器asp.net采用了4.0的版本,则默认会阻止客户端的html内容提交,提交 ...
- IIS中的上传目录权限设置问题
虽然 Apache 的名声可能比 IIS 好,但我相信用 IIS 来做 Web 服务器的人一定也不少.说实话,我觉得 IIS 还是不错的,尤其是 Windows 2003 的 IIS 6(马上 Lon ...
- IIS中启用ASP并连接Access数据库的解决办法
1. IIS安装ASP模块 进入控制面板 ---- 打开或关闭Windows功能 选择如下所示两项,点击安装完成 2. 打开父路径许可 选择相应应用程序池 ----- 高级设置 ---- 将“启用父路 ...
- 关于 IIS 中 Excel 访问的问题
关于 IIS 上 Excel 文件的访问, 一路上困难重重, 最后按以下步骤进行设置, 可在 IIS 中正常使用! 1. 引用及代码: 1). 项目中添加 Excel 程序集引用(注意: 从系统 CO ...
- 【续集】在 IIS 中部署 ASP.NET 5 应用程序遭遇的问题
dudu 的一篇博文:在 IIS 中部署 ASP.NET 5 应用程序遭遇的问题 针对 IIS 部署 ASP.NET 5 应用程序的问题,在上面博文中主要采用两种方式尝试: VS2015 的 Publ ...
- 【记录】从客户端()中检测到有潜在危险的 Request.Path 值。
从客户端()中检测到有潜在危险的 Request.Path 值. 错误信息: Application_Error Url: www.cnblogs.com/%E5%BA%.... UserAgent: ...
随机推荐
- Ajax及跨域
概念 Ajax Ajax,Asynchronous JavaScript and XML,字面意思:异步的 JavaScript 和 XML,是指一种创建交互式网页应用的网页开发技术. 用于异步地去获 ...
- 简单入门canvas - 通过刮奖效果来学习
一 .前言 一直在做PC端的前端开发,从互联网到行业软件.最近发现移动端已经成为前端必备技能了,真是不能停止学习.HTML5新增的一些东西,canvas是用的比较多也比较复杂的一个,简单的入门了一下, ...
- [C#] 了解过入口函数 Main() 吗?带你用批处理玩转 Main 函数
了解过入口函数 Main() 吗?带你用批处理玩转 Main 函数 目录 简介 特点 方法的参数 方法的返回值 与批处理交互的一个示例 简介 我们知道,新建一个控制台应用程序的时候,IDE 会同时创建 ...
- 【Machine Learning】Python开发工具:Anaconda+Sublime
Python开发工具:Anaconda+Sublime 作者:白宁超 2016年12月23日21:24:51 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现 ...
- Web安全相关(五):SQL注入(SQL Injection)
简介 SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据 ...
- ABAP单元测试最佳实践
本文包含了我在开发项目中经历过的实用的ABAP单元测试指导方针.我把它们安排成为问答的风格,欢迎任何人添加更多的Q&A's,以完成这个列表. 在我的项目中,只使用传统的ABAP report. ...
- 我认为JS还可以改进的点
曾经我一度在寻找JS的替代语言,尝试过CoffeeScript/TypeScript/Dart(都是浅尝).不为什么原因,而是当你写的越多的JS,越觉得JS很多时候显得很操蛋.好在ES2015和Bab ...
- iOS开发系列--通讯录、蓝牙、内购、GameCenter、iCloud、Passbook系统服务开发汇总
--系统应用与系统服务 iOS开发过程中有时候难免会使用iOS内置的一些应用软件和服务,例如QQ通讯录.微信电话本会使用iOS的通讯录,一些第三方软件会在应用内发送短信等.今天将和大家一起学习如何使用 ...
- MVVM大比拼之vue.js源码精析
VUE 源码分析 简介 Vue 是 MVVM 框架中的新贵,如果我没记错的话作者应该毕业不久,现在在google.vue 如作者自己所说,在api设计上受到了很多来自knockout.angularj ...
- EasyPR--中文开源车牌识别系统 开发详解(1)
在上篇文档中作者已经简单的介绍了EasyPR,现在在本文档中详细的介绍EasyPR的开发过程. 正如淘宝诞生于一个购买来的LAMP系统,EasyPR也有它诞生的原型,起源于CSDN的taotao123 ...