一、介紹
Quartz.net是Quartz的.net版本,主要用途是用來管理定時需要執行的任務,和數據庫的job有點類似,他管理的任務包括但不限於數據,還可以包括類似於發送郵件,短信等任務,更可以查看任務狀態,總而言之,是一個強大,開源且輕量級的任務調度框架。
官網:http://www.quartz-scheduler.net/
在園子里其實已經有很多人已經寫過Quartz.net的相關文章了,在研究Quartz.net的過程中也借鑒了很多他們的相關經驗,並將一些想法記錄下來,以供以后參考。
二、簡單的Job
[DisallowConcurrentExecutionAttribute] public class HelloJob: IJob { public Task Execute(IJobExecutionContext context) { Console.WriteLine("Info From HelloJob"); Thread.Sleep(30000); LogHelper.WriteInfo("Info From HelloJob"); return Task.FromResult(0); } }
普通的job繼承IJob就可以,上面的代碼是像系統中寫日志,在控制台調用如下。
static void Main(string[] args) { //創建一個作業調度池 ISchedulerFactory schedf = new StdSchedulerFactory(); IScheduler sched = schedf.GetScheduler(); //創建出一個具體的作業 IJobDetail job = JobBuilder.Create<HelloJob>().Build(); //配置一個觸發器 ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().WithSimpleSchedule(x=>x.WithIntervalInSeconds(3).WithRepeatCount(int.MaxValue)).Build(); //加入作業調度池中 sched.ScheduleJob(job, trigger); //開始運行 sched.Start(); Console.ReadKey(); }
其中調度器就是一個管理者,他管理着他控制范圍內的所有的job的開始,暫停等信息。具體的作業,也就是上面的Job,這個Job會和一個觸發器相關聯,這個觸發器用來控制Job的觸發事件,觸發次數等,在Quartz.net中有兩種觸發器類型,一種是簡單觸發器,也就是上面的ISimpleTrigger接口,還有一種是Cron類型的觸發器,對應的接口名是ICronTrigger,他使用cron表達式來描述Job的觸發事件,不了解cron表達式的可以百度具體代表的意思,這里就不詳述了。
三、持久化job到本地
上面的代碼只是Quartz的簡單使用,但是不能可視化的控制調度池內的job。上面說到Quartz.net很強大,要想做到這一點也很簡單,將job持久化到本地,將調度器,job詳情,相關觸發器的信息都抽象成數據存儲在數據庫中就行了。
quartz.net的github內提供了多種數據庫的建表腳本,大家可以根據自己的需要去取,地址是:https://github.com/quartznet/quartznet/tree/master/database/tables,我用的是sqlServer版本的,只需要改一下數據庫的名稱就行。
表建好之后需要在程序中初始化相關配置,初始化的代碼如下:
public async static Task<IScheduler> GetScheduler() { try { if (scheduler == null) { #region quartz 實例配置 還包括集群,線程池等配置,可單獨放到config文件中配置 var properties = new NameValueCollection(); //存儲類型 properties["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz"; properties["quartz.serializer.type"] = "binary"; //表明前綴 properties["quartz.jobStore.tablePrefix"] = "QRTZ_"; //驅動類型 properties["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz"; //數據源名稱 properties["quartz.jobStore.dataSource"] = "Quartz"; //連接字符串 properties["quartz.dataSource.Quartz.connectionString"] = ConfigurationManager.AppSettings["quartzConnect"]; //sqlserver版本 properties["quartz.dataSource.Quartz.provider"] = "SqlServer"; //最大鏈接數 properties["quartz.dataSource.Quartz.maxConnections"] = "5"; #endregion ISchedulerFactory sf = new StdSchedulerFactory(properties); scheduler =await sf.GetScheduler(); LogHelper.WriteInfo(ConfigurationManager.AppSettings["quartzConnect"].ToString()); LogHelper.WriteInfo("任務調度初始化成功"); } } catch (Exception ex) { LogHelper.WriteError("任務調度初始化失敗!", ex); } return scheduler; }
由於我從NuGet應用的Quartz是3.0.7.0版本的,方法都是異步的,所以都寫成了異步方法(c#的異步還沒怎么理解透徹,寫法可能有誤,請諒解)。這些配置因為版本經常會更新,所以不同的時期可能會有所不同,大家可以百度最新的配置。配置完成之后就可以調用該方法獲取最新的調度器,然后對調度器內的Job進行控制了,詳細的代碼會文末會給出GitHub的地址,有需要的可以去GitHub上clone。
Job能夠持久化了,如果代碼只能點擊exe文件運行,那持久化就沒什么意義了,所以我選擇使用Topshelf來創建一個服務,作為服務端來一直運行,服務啟動時就初始化調度器。調用的代碼如下:
static void Main(string[] args) { FileInfo fi = new FileInfo(AppDomain.CurrentDomain.BaseDirectory + "Web.config"); XmlConfigurator.ConfigureAndWatch(fi); LogHelper.SetConfig(fi); HostFactory.Run(config => { config.Service<QuartzHelper>(setting => { setting.ConstructUsing(name => new QuartzHelper()); setting.WhenStarted( tc => tc.start()); setting.WhenStopped( tc => tc.StopSchedule()); }); config.RunAsLocalSystem(); config.SetDescription("Quartz初使用"); config.SetDisplayName("QuartzService"); config.SetServiceName("QuartzService"); }); }
四、管理Job
持久化完成之后,就需要寫個管理端來管理Job了,在這里我選擇使用傳統的MVC建一個管理端,為了圖方便,我使用了曉道的管理端框架,頁面如下:

這里的Job就是上面的HelloJob,需要說明一下的是,在新增的時候,類名需要和Job的名稱保持一致,因為在代碼中需要通過類名字段來反射找到dll文件中的Job,比如這里的類名我填的就是HelloJob,前面的命名空間不需要填。添加完成之后啟動使用Topshelf創建的服務:

服務啟動完成之后就可以看到記錄的日志了:


五、末尾
要想更加深入了解Quartz.net的同學,可以看看張善友大神的系列文章。
代碼已經上傳到GitHub上了,GitHub的地址為:https://github.com/cpf121/Quartz.net-Demo 。代碼拉下來后運行方式如下:
1.去GitHub取到最新的建表腳本,自己建表,並修改config文件中的連接語句
2.命令提示符使用管理員權限找到QuartzService文件夾下的QuartzService.exe文件,運行QuartzService.exe Install
3.在管理端添加對應的Job信息。
