使用FluentScheduler和IIS预加载在asp.net中实现定时任务管理
FluentScheduler介绍
github地址:https://github.com/fluentscheduler/FluentScheduler
FluentScheduler是一个简单的任务调度框架,使用起来非常方便,这个框架也是我在搜索iis预加载的时候偶然间发现的,立马拿来试用一下,感觉爽呆了,当然还有Quarz.Net之类的其他任务管理框架,不过看配置似乎有点麻烦,反正除了timer我啥也没用过...
之前还花费了很长一段时间自己写了一套定时任务的框架,如今看到FluentScheduler我已经决定将之前的废弃了...
好吧,废话不多说,框架调用非常简单,所以直接上代码了,其实我做的只不过是把英文翻译一下
FluentScheduler使用
.net 框架:.net framework 4.5
项目:.net mvc5
如果要在winform,wpf之类的项目中使用是完全没有问题的,因为本文最终的目标是实现将该web项目作为一个定时任务的服务,所以选择了以上的架构
1.引用nuget包:FluentScheduler
2.Application_Start函数加上:
//初始化任务管理器
JobManager.Initialize(new MyRegistry());
3.MyRegistry.cs
public class MyRegistry : Registry
{
public MyRegistry()
{
// Schedule an IJob to run at an interval
// 立即执行每10秒一次的计划任务。(指定一个时间间隔运行,根据自己需求,可以是秒、分、时、天、月、年等。)
Schedule<MyJob>().ToRunNow().AndEvery(10).Seconds();
// 立即执行每10秒一次的计划任务。如果本次任务没有结束,下一次的任务则不会开始,禁止并行运行
Schedule<MyJob>().NonReentrant().ToRunNow().AndEvery(10).Seconds();
//在每天的21:15执行计划任务
Schedule(() => Console.WriteLine("It's 9:15 PM now.")).ToRunEvery(1).Days().At(21, 15);
// 立即执行一个在每月的第一个星期一 3:00 的计划任务
Schedule(() => Console.WriteLine("It's 3:00 AM now.")).ToRunNow().AndEvery(1).Months().OnTheFirst(DayOfWeek.Monday).At(3, 0);
//在每周一的21:15执行计划任务
Schedule(() => Console.WriteLine("It's 9:15 PM now.")).ToRunEvery(1).Weeks().On(DayOfWeek.Monday).At(21, 15);
}
}
上面需要注意的是NonReentrant
函数的使用,在某些特殊的业务里可能任务执行的时间比定时循环的间隔时间要长,这时候你就要考虑是否允许并行运行两个同样的任务,NonReentrant就是用来解决这个问题的
4.MyJob.cs
public class MyJob : IJob, IRegisteredObject
{
private readonly object _lock = new object();
private bool _shuttingDown;
private static Logger logger = LogManager.GetCurrentClassLogger(); //初始化日志类
public MyJob()
{
HostingEnvironment.RegisterObject(this);
}
public void Execute()
{
try
{
lock (_lock)
{
if (_shuttingDown)
return;
logger.Info("开始工作:" + DateTime.Now);
Thread.Sleep(60*1000);
logger.Info("工作结束:" + DateTime.Now);
}
}
finally
{
HostingEnvironment.UnregisterObject(this);
}
}
public void Stop(bool immediate)
{
logger.Info("调用stop:" + DateTime.Now);
lock (_lock)
{
logger.Info("lock结束:" + DateTime.Now);
_shuttingDown = true;
}
HostingEnvironment.UnregisterObject(this);
}
}
上面是一个简单的示例,所有的业务逻辑都在Execute函数中执行,如果不在web项目中运行,则不需要实现IRegisteredObject接口以及stop函数,所有的业务代码均在Execute
函数中执行
在ASP.NET中作定时任务
在之前我们也有部分项目用widowsservice来做定时任务,但是弊端很明显,调试太麻烦,发布也麻烦,自动发布更难实现
相比之下web服务器就容易管理的多了
实际上在asp.net 中的定时任务和FluentScheduler框架并没有什么必然的联系,你也可以用timer或其他的任何方式来实现,但是所有的这些实现方式都避免不了面对一个问题:IIS的回收机制
因为有了回收机制的存在,所以在asp.net中做定时任务就会面临两个问题:
1.任务没有执行完成线程就被回收了
2.线程回收之后,只有在下一次访问网站的时候任务才会再次启动
首先我们来解决第一个问题:
对于iis的回收,我们需要做的其实并不是阻止它的回收,实际上我试过各种方式都无法完全阻挡iis的回收,不知道是否是方法没有用对。
但是我们可以保证当前的任务执行完毕再进行回收
方式就是实现IRegisteredObject
接口,以上面的MyJob类为例,我们通过调用HostingEnvironment.RegisterObject方法在ASP.NET中注册它
通过调用HostingEnvironment.UnregisterObject方法释放服务
当Appdomain要被回收的时候,会调用已注册对象IRegisteredObject中的Stop方法。
//
// 摘要:
// Requests a registered object to unregister.
//
// 参数:
// immediate:
// true to indicate the registered object should unregister from the hosting environment
// before returning; otherwise, false.
void Stop(bool immediate);
在第一次调用stop方法时,参数为false,执行完毕后,如果没有调用HostingEnvironment.UnregisterObject
函数,隔30秒stop方法会再次被调用,参数为true,如果仍然没有调用HostingEnvironment.UnregisterObject
函数,该服务就会被移除
不过我们使用的过程中并不会考虑第二次的调用,因为在第一次stop函数被调用的时候我们就会lock住正在执行的任务,并且一直到任务执行完成再释放lock,最后调用HostingEnvironment.UnregisterObject保证任务正常退出
对于这个流程上面的Myjob就是FluentScheduler提供的一个示例
IIS预加载
应用程序池回收之后,如果没有人访问网站,w3wp是不会启动的,那也就代表着我们的定时任务就不会启动了,所以我们需要在程序池被回收之后模拟访问一下该网站,我们可以通过写一个定时的程序每隔一秒钟访问一遍该网站来解决这个问题,但是为了解决这个问题多写一个程序并没有必要,因为微软已经提供了一个网站预加载的功能,每当应用程序池被回收,系统就会启动一个进程模拟访问一遍网站。这个功能似乎是iis7之后就有了,我下面演示的iis10的界面,其他版本的界面可能会稍微有所不同
1.修改应用程序池启动模式
2.开启对应网站预加载
3.增加配置编辑器,编写默认预加载的请求页面
至此,我们的服务就可以正常的运行啦
使用FluentScheduler和IIS预加载在asp.net中实现定时任务管理的更多相关文章
- ASP.NET MVC3 Razor 调试与预加载
目录(?)[-] 获取服务器信息 FormsAuthenticationSlidingExpiration 属性 MVC3预加载 在ASP.NET MVC3开发中,调试中怎么也是不可缺少的,那对于 ...
- Angular - 预加载 Angular 模块
Angular - 预加载延迟模块 在使用路由延迟加载中,我们介绍了如何使用模块来拆分应用,在访问到这个模块的时候, Angular 加载这个模块.但这需要一点时间.在用户第一次点击的时候,会有一点延 ...
- JS 实现图片的预加载(转载)
图片预加载是web开发中一种应用相当广泛的技术,比如我们在做图片翻转显示等特效的时候,为了让图片在转换的时候不出现等待,我们最好是先让图片下载到本地,然后在继续执行后续的操作. 下面的函数实现了一个我 ...
- 预加载与智能预加载(iOS)
来源:Draveness(@Draveness) 链接:http://www.jianshu.com/p/1519a5302141 前两次的分享分别介绍了 ASDK 对于渲染的优化以及 ASDK 中使 ...
- Javascript实现图片的预加载的完整实现
图片预加载是web开发中一种应用相当广泛的技术,比如我们在做图片翻转显示等特效的时候,为了让图片在转换的时候不出现等待,我们最好是先让图片下载到本地,然后在继续执行后续的操作.今天我们将来实现一个完整 ...
- 57.fielddata预加载机制以及序号标记预加载
如果真的要对分词的field执行聚合,那么每次都在query-time的同时由es生成fielddata并加载到内存中来,速度可能会比较慢,性能很差,改善性能的方式就是预先生成fielddata值并加 ...
- 图片预加载的插件使用-jquery.imgpreload.min.js
使用方法: //图片预加载 var the_images = [];//新建一个数组,然后将要加载的图片地址推入这个数组中: the_images.push( 'bg.jpg' ); var load ...
- IIS初始化(预加载),解决第一次访问慢,程序池被回收问题
你以为你可以慢,那是不可能的!你以为你可以不动,那也是不可能的! 河南是守株待兔故事情节的发源地,讲的是懒惰的农夫坐在树桩旁等待可爱的小毛兔撞树的故事,那么这种事情怎么可能天天出现呢!你以为的事并一定 ...
- 【转】IIS初始化(预加载),解决第一次访问慢,程序池被回收问题
原地址:http://www.debugrun.com/a/mpyWXwg.html 读在最前面: 1.本文以IIS8,Windows Server 2012R2做为案例 2.IIS8 运行在 Win ...
随机推荐
- 网站开发进阶(三十一)js如何将html表格导出为excel文件(后记)
js如何将html表格导出为excel文件(后记) 前言 项目前期做了个导出Excel表格的功能,但是经过测试发现只有在IE上才可以正确实现,在Chrome等浏览器中无法实现导出效果.经过上网搜索,尝 ...
- ubuntu14.04系统中virtualbox安装Oracle VM VirtualBox Extension Pack包
ubuntu14.04系统中virtualbox默认不支持usb设备,需要安装Oracle VM VirtualBox Extension Pack才行,但必须安装以下版本才可以安装成功: Oracl ...
- 2014新年福利,居然有人将Ext JS 4.1的文档翻译了
原文:http://damoqiongqiu.iteye.com/blog/1998022
- UML之对象图
对象图对包含在类图中的事物的实例建模,对象图显示了在某一时间点上一组对象以及他们之间的关系.对象图用于对系统的静态设计视图或静态交互视图建模,这包括对某一时刻的系统快照建模,表示出对象集.对象的状态以 ...
- LeetCode之“链表”:在O(1)时间删除链表节点
下边讨论暂不包括尾节点. 一般来说,我们要删除链表中的一个节点是需要知道其上一节点的.但我们真的需要吗? 其实我们可以将待删节点的下一节点的值和指向的下一节点赋予待删节点,然后删除待删节点的下一节点. ...
- java http缓存
HTTP/1.1中缓存的目的是为了在很多情况下减少发送请求,也即直接返回缓存:同时在许多情况下可以不需要发送完整响应.前者减少了网络回路的数量,挺高响应速度,HTTP利用一个"过期(expi ...
- linux上 java 使用 javasqlite
linux上 java 使用 javasqlite http://www.ch-werner.de/javasqlite/ 1) 下载: http://www.ch-werner.de/javasql ...
- Linux - 用make进行工程编译
首先建立好自己的工作目录 然后创建主函数main.cpp 接着写sinValue.h和cosValue.h函数文件 先按照传统方式进行编译运行 然后用make,先写makefile文件 将原来生成的文 ...
- 关于SharePoint2007简单随感
首先,还是要感谢我毕业以后的这第一份正式工作,当然现在也依然在做,带我走进了SharePoint的世界,很奇妙也许是有缘吧,自己不是个努力的人,从面试的时候对Moss这个东西闻所未闻,到现在一知半解, ...
- MATLAB坐标系中绘制图片
MATLAB坐标系中绘制图片 方法一 使用图片坐标循环的方式,代码如下. clear,clc,close all tic; map=imbinarize(imread('map.bmp'));%map ...