Quartz.NET實現做業調度

1、Quartz.NET介紹

Quartz.NET是一個強大、開源、輕量的做業調度框架,是 OpenSymphony 的 Quartz API 的.NET移植,用C#改寫,可用於winform和asp.net應用中。它靈活而不復雜。你可以用它來爲執行一個做業而建立簡單的或複雜的做業調度。它有不少特徵,如:數據庫支持,集羣,插件,支持cron-like表達式等等。html

通俗說它的功能是:好比說我想天天晚上2點讓程序或網站執行某些代碼,或者每隔5秒種我想查看是否有新的任務要處理等。java

官網:http://www.quartz-scheduler.net/git

源碼:https://github.com/quartznet/quartznetgithub

示例:http://www.quartz-scheduler.net/documentation/quartz-2.x/quick-start.html數據庫

其實Quartz是一個徹底由java編寫的開源做業調度框架,Quartz是OpenSymphony開源組織在Job scheduling領域又一個開源項目,它能夠與J2EE與J2SE應用程序相結合也能夠單獨使用。Quartz能夠用來建立簡單或爲運行十個,百個,甚至是好幾萬個Jobs這樣複雜的程序。而Quartz.Net與NPOI同樣是一個DoNet平臺下的對應版本。若是您使用Java直接訪問這裏就行了http://www.quartz-scheduler.org/express

2、依賴框架

引入框架的方法很是簡單你能夠直接用nuget管理包也能夠在項目中添加引用:json

2.一、使用Nuget添加引用

2.1.0、建立一個項目

建立一個新項目,能夠是ASP.NET MVC,WebForms,Winforms等多種.Net項目,這裏使用的是VS2013,建立了一個MVC項目:api

2.1.一、安裝Nuget

新版本的Visual Studio默認狀況是安裝了Nuget的,如Visual Studio2015,但若是沒有安裝,打開VS菜單「工具」->"擴展與更新"服務器

在擴展與更新中搜索「nuget」,能夠新安裝或卸載後升級:網絡

2.1.二、修改Nuget鏡像

爲解決國內訪問NuGet服務器速度不穩定的問題建議你最好選擇一些鏡像服務器,這樣能夠加速下載。

在Visual Studio中的添加方法是:打開「工具」->「選項」菜單

在左側菜單中找到「NuGet包管理器」

點擊右上角的加號,添加兩個鏡像,這些地址能夠上網搜索,我使用的是以下兩個:

https://nuget.cnblogs.com/v3/index.json

http://api.nuget.org/v3/index.json

設置一下順序就OK了。

2.1.三、使用nuget安裝Quartz.NET

點擊「工具」->"NuGet包管理器"->「程序包管理器控制檯」

輸入安裝包的命令:

Install-Package Quartz

安裝結果以下:

此時包管理器中就下載了須要的程序集與相關文件,程序中也添加了引用。

 

2.二、手動引用

固然若是您不肯意使用nuget也能夠下載到Quartz後直接引用,能夠在本文尾部下載到框架。

框架下載地址:連接: https://pan.baidu.com/s/1slDM5JJ 密碼: 9x5m

3、應用框架

假定我如今想當前的MVC應用每隔5秒鐘向C:\Quartz.txt文件中記錄當前時間

由於這是一個Web應用,我想網站一啓動時就開始該項工做,這裏咱們須要打開Global.asax,將代碼寫在Application_Start方法中

3.一、定義要執行的任務

定義一個類,實現Quartz.IJob接口,實現方法Execute,TimeJob.cs文件的代碼以下:

using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MvcApplication1
{
    public class TimeJob : IJob
    {
        public void Execute(IJobExecutionContext context)
        {
            //向c:\Quartz.txt寫入當前時間並換行
            System.IO.File.AppendAllText(@"c:\Quartz.txt", DateTime.Now+Environment.NewLine);
        }
    }
}

3.二、建立一個調度器

調度器負責管理與控制任務的執行,在Global.asax文件的Application_Start方法中添加以下代碼:

            //調度器
            IScheduler scheduler;
            //調度器工廠
            ISchedulerFactory factory;

            //建立一個調度器
            factory = new StdSchedulerFactory();
            scheduler = factory.GetScheduler();
            scheduler.Start();

3.三、建立一個任務對象

這個任務對象就是咱們將要執行的工做,job1是名稱,group1是組名。

            //二、建立一個任務
            IJobDetail job = JobBuilder.Create<TimeJob>().WithIdentity("job1", "group1").Build();

3.四、建立一個觸發器

觸發器定義了什麼時間任務開始或每隔多久執行一次。

            //三、建立一個觸發器
            //DateTimeOffset runTime = DateBuilder.EvenMinuteDate(DateTimeOffset.UtcNow);
            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity("trigger1", "group1")
                .WithCronSchedule("0/5 * * * * ?")     //5秒執行一次
                //.StartAt(runTime)
                .Build();

3.五、將任務與觸發器添加到調度器中並執行

            //四、將任務與觸發器添加到調度器中
            scheduler.ScheduleJob(job, trigger);
            //五、開始執行
            scheduler.Start();

3.六、應用關閉時結束任務

當網站關閉時結束正在執行的工做,在Global.asax中的Application_End方法中添加以下代碼:

        protected void Application_End(object sender, EventArgs e)
        {
            //   在應用程序關閉時運行的代碼
            if (scheduler != null)
            {
                scheduler.Shutdown(true);
            }
        }

shutdown方法中的參數true的意思爲:是否等待任務的完成再結束。

3.七、運行結果

3.八、Global.asax中的完整代碼

using Quartz;
using Quartz.Impl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace MvcApplication1
{
    public class MvcApplication : System.Web.HttpApplication
    {
        //調度器
        IScheduler scheduler;
        //調度器工廠
        ISchedulerFactory factory;
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();

            //一、建立一個調度器
            factory = new StdSchedulerFactory();
            scheduler = factory.GetScheduler();
            scheduler.Start();

            //二、建立一個任務
            IJobDetail job = JobBuilder.Create<TimeJob>().WithIdentity("job1", "group1").Build();

            //三、建立一個觸發器
            //DateTimeOffset runTime = DateBuilder.EvenMinuteDate(DateTimeOffset.UtcNow);
            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity("trigger1", "group1")
                .WithCronSchedule("0/5 * * * * ?")     //5秒執行一次
                //.StartAt(runTime)
                .Build();

            //四、將任務與觸發器添加到調度器中
            scheduler.ScheduleJob(job, trigger);
            //五、開始執行
            scheduler.Start();
        }

        protected void Application_End(object sender, EventArgs e)
        {
            //   在應用程序關閉時運行的代碼
            if (scheduler != null)
            {
                scheduler.Shutdown(true);
            }
        }
    }
}

4、框架說明

看官方的示例、源碼或幫助文檔能夠了解更多的使用方法,官方幫助的地址是:https://www.quartz-scheduler.net/documentation/index.html

4.一、Quartz的cron表達式

cron表達式就是用於設定時間的一個字符串,在前面的代碼中咱們就用到了,以下所示:

            //三、建立一個觸發器
            //DateTimeOffset runTime = DateBuilder.EvenMinuteDate(DateTimeOffset.UtcNow);
            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity("trigger1", "group1")
                .WithCronSchedule("0/5 * * * * ?")     //5秒執行一次
                //.StartAt(runTime)
                .Build();

官方英文介紹:http://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/crontrigger.html

cron expressions 總體上仍是很是容易理解的,只有一點須要注意:"?"號的用法,看下文能夠知道「?」能夠用在 day of month 和 day of week中,他主要是爲了解決以下場景,如:每個月的1號的每小時的31分鐘,正確的表達式是:* 31 * 1 * ?,而不能是:* 31 * 1 * *,由於這樣表明每週的任意一天。

/*
由7段構成:秒 分 時 日 月 星期 年(可選)

"-" :表示範圍  MON-WED表示星期一到星期三
"," :表示列舉 MON,WEB表示星期一和星期三
"*" :表是「每」,每個月,天天,每週,每一年等
"/" :表示增量:0/15(處於分鐘段裏面) 每15分鐘,在0分之後開始,3/20 每20分鐘,從3分鐘之後開始
"?" :只能出如今日,星期段裏面,表示不指定具體的值
"L" :只能出如今日,星期段裏面,是Last的縮寫,一個月的最後一天,一個星期的最後一天(星期六)
"W" :表示工做日,距離給定值最近的工做日
"#" :表示一個月的第幾個星期幾,例如:"6#3"表示每月的第三個星期五(1=SUN...6=FRI,7=SAT)

若是Minutes的數值是 '0/15' ,表示從0開始每15分鐘執行

若是Minutes的數值是 '3/20' ,表示從3開始每20分鐘執行,也就是‘3/23/43’
*/

官方示例:

表達式 解釋
0 0 12 * * ? 天天中午12點觸發
0 15 10 ? * * 天天上午10:15觸發
0 15 10 * * ? 天天上午10:15觸發
0 15 10 * * ? * 天天上午10:15觸發
0 15 10 * * ? 2005 2005年的天天上午10:15觸發
0 * 14 * * ? 在天天下午2點到下午2:59期間的每1分鐘觸發
0 0/5 14 * * ? 在天天下午2點到下午2:55期間的每5分鐘觸發
0 0/5 14,18 * * ? 在天天下午2點到2:55期間和下午6點到6:55期間的每5分鐘觸發
0 0-5 14 * * ? 在天天下午2點到下午2:05期間的每1分鐘觸發
0 10,44 14 ? 3 WED 每一年三月的星期三的下午2:10和2:44觸發
0 15 10 ? * MON-FRI 週一至週五的上午10:15觸發
0 15 10 15 * ? 每個月15日上午10:15觸發
0 15 10 L * ? 每個月最後一日的上午10:15觸發
0 15 10 L-2 * ? 每月的次日到最後一天的上午10:15觸發
0 15 10 ? * 6L 每個月的最後一個星期五上午10:15觸發
0 15 10 ? * 6L 每月最後一個星期五上午10時15分觸發
0 15 10 ? * 6L 2002-2005 2002年至2005年的每個月的最後一個星期五上午10:15觸發
0 15 10 ? * 6#3 每個月的第三個星期五上午10:15觸發
0 0 12 1/5 * ? 每個月每隔5天下午12點(中午)觸發, 從每個月的第一天開始
0 11 11 11 11 ? 每11月11日上午11時11分觸發

4.二、其它幫助

請查看幫助文檔、示例或上網搜索,:),後面有空再補充吧

4.三、IIS應用程序池自動回收問題的有效解決辦法

IIS能夠設置定時自動回收,默認回收是1740分鐘,也就是29小時。IIS自動回收至關於服務器IIS重啓,應用程序池內存清空,全部數據被清除,至關於IIS重啓,在度量快速開發平臺服務器端,爲了減少數據庫負擔,內存中暫存了不少信息,不適合頻繁的回收,由於回收會形成服務器端全部存在內存中的數據丟失,若是沒有及時保存到數據庫中,可能致使程序出現問題。而若是系統使用高峯時期,並不適合回收,回收可能致使幾十秒IIS無響應,對於正在工做的人員來講,是一種很很差的體驗,會覺得是網絡或者掉線等問題。

若是IIS重啓則Global.asax中的方法將被再次執行,若是不想IIS自動重啓可使用以下的設置:

IIS應用程序池回收,找到相應的應用程序池並點擊高級設置,就能夠看到回收的相關設置

發生配置更改時禁止回收:若是爲True,應用程序池在發生配置更改時將不會回收。

固定時間間隔(分鐘):超過設置的時間後,應用程序池回收,爲0意味着應用程序池不會按固定間隔回收。系統默認設置的時間是1740(29小時)。

禁用重疊回收:若是爲true,將發生應用程序池回收,以便在建立另外一個工做進程以前退出現有工做進程。

請求限制:應用程序池在回收以前能夠處理的最大請求數。若是值爲0,則表示應用程序池能夠處理的請求數沒有限制。

生成回收事件日誌條目:每發生一次指定的回收事件時便產生一個事件日誌條目。

更多參考:http://www.cnblogs.com/Fishwood/p/3602041.html

5、總結

一、實現定時任務的方法有不少,若是很是簡單的話直接使用系統內置的Timer,Scheduler,Cache都是能夠達到的,但要注意GC回收的問題,通常會定義成靜態的。

二、本文只是很是粗淺的介紹了一下零配置的方法,您也能夠選擇使用XML配置的方式替代部分的硬編碼。

6、下載

示例下載 密碼: 9x5m

框架下載 密碼: 9x5m

相關文章
相關標籤/搜索