最近,在工作中遇到了 Quartz.net 這個組件,為了更好的理解項目代碼的來龍去脈,於是決定好好的研究一下這個東西。確實是好東西,既然是好東西,我就拿出來分享一下。萬丈高樓平地起,我們也從入門開始吧。
歡迎使用 Quartz.NET 快速入門指南。 在閱讀本指南時,必須注意以下條目:
1、下載 Quartz.NET
2、安裝 Quartz.NET
3、根據您自己的特定需求來配置 Quartz.Net
4、展示一個示例應用程序
一、下載並安裝
您可以直接下載 ZIP 文件或使用 NuGet 包來獲取文件。二者是有區別的,NuGet 包只包含運行 Quartz.NET 所必須的二進制文件,ZIP 文件就不一樣了,包含源代碼、示例和 Quartz.NET 服務器示例應用程序。
Zip文件
簡短版本:如果你成功下載了 Quartz.NET 壓縮包文件,只要將 ZIP 文件解壓,從bin目錄中獲取 Quartz.dll 文件,就可以開始使用它了。
Quartz.Net 的核心庫是一個非常干凈和獨立的類庫,不會強行依賴任何其他的二進制文件。 如果您想使用JSON.NET進行JSON序列化時,您可以根據需要選擇加入更多的程序集。同時您只要保證在應用程序中包含了 Quartz.dll 文件就可以成功運行 Quartz.NET,也會和其他的二進制文件相處融洽。 因此,只要將 Quartz.dll 文件添加到使用它們的 Visual Studio 項目中就可以完美的運行。 您可以從路徑bin \ your-target-framework-version \ release \ Quartz 中提取的文檔中找到這些 dll。
二、NuGet包
這是最簡單的做法了,只需啟動Visual Studio(安裝了NuGet)並從包管理器擴展中添加對Quartz包的引用:
1、右鍵單擊項目的“引用”(References),然后選擇“管理 NuGet 程序包(N)”(Manage NuGet Packages(N)) ...
2、從左側選擇“瀏覽or在線”類別
3、在左上方的搜索中輸入 Quartz,然后按 回車 鍵
4、從搜索結果中選擇 Quartz.NET 並點擊安裝
5、完成!
或者使用NuGet的命令行來安裝:
Install-Package Quartz
如果想要添加 JSON 序列化的功能,只需以相同的方式添加 Quartz.Serialization.Json 包就可以。
三、配置
Quartz.NET 是一個支持靈活配置的庫。Quartz.NET 提供三種的配置信息的方式(不相互排斥):
1、以編程方式通過向調度程序工廠提供 NameValueCollection 參數
2、通過使用 quartz-element 的標准 youapp.exe.config 配置文件(僅限完整的.NET框架)
3、可以使用應用程序根目錄中的 quartz.config 文件(適用於.NET Core和完整的.NET Framework)
您可以在Quartz.NET zip文件中找到所有這些替代品的樣本。
Quartz Configuration Reference中提供了可用屬性的完整文檔。
為了加速啟動和運行,提供了最基本的配置信息的文件 quartz.config 看起來應該像這樣:
quartz.scheduler.instanceName = MyScheduler quartz.jobStore.type = Quartz.Simpl.RAMJobStore,Quartz quartz.threadPool.threadCount = 3
請記住在 Visual Studio 的文件屬性頁上設置“復制到輸出目錄”以使值始終為“復制”。否則,配置文件就不會存在構建項目的目錄中,就不會使用該配置文件。
此配置創建的調度程序具有以下特征:
quartz.scheduler.instanceName - 此調度程序的名稱將為“MyScheduler”。
quartz.threadPool.threadCount - 最多可同時運行3個作業。
quartz.jobStore.type - 所有 Quartz 的數據,例如作業和觸發器的詳細信息,都保存在內存中(而不是數據庫中)。即使你有一個數據庫並希望在 Quartz 中使用它,我建議你在使用數據庫打開一個全新的維度之前讓 Quartz 使用 RamJobStore。
實際上,如果你不想定義這些屬性,Quartz.NET會提供合理的默認值
四、先看一個簡單的示例程序
現在您已經下載並安裝了Quartz,現在是時候啟動並運行一個示例應用程序了。 以下代碼獲取調度程序的實例,啟動它,然后將其關閉:
1 using System; 2 using System.Threading.Tasks; 3 4 using Quartz; 5 using Quartz.Impl; 6 7 namespace QuartzSampleApp 8 { 9 public class Program 10 { 11 private static void Main(string[] args) 12 { 13 // trigger async evaluation 14 RunProgram().GetAwaiter().GetResult(); 15 } 16 17 private static async Task RunProgram() 18 { 19 try 20 { 21 // 從Factory獲取Scheduler實例 22 NameValueCollection props = new NameValueCollection 23 { 24 { "quartz.serializer.type", "binary" } 25 }; 26 StdSchedulerFactory factory = new StdSchedulerFactory(props); 27 IScheduler scheduler = await factory.GetScheduler(); 28 29 // 並啟動它 30 await scheduler.Start(); 31 32 // some sleep to show what's happening 33 await Task.Delay(TimeSpan.FromSeconds(10)); 34 35 // 當您准備關閉程序時,最后關閉調度程序 36 await scheduler.Shutdown(); 37 } 38 catch (SchedulerException se) 39 { 40 await Console.Error.WriteLineAsync(se.ToString()); 41 } 42 } 43 } 44 }
從Quartz 3.0開始,當在scheduler.Shutdown() 之后沒有剩下的代碼要執行時,你的應用程序將終止,因為沒有任何活動的線程。 如果希望在處理Task.Delay和Shutdown之后調度程序繼續運行,則應手動阻止退出應用程序。
現在運行該程序將不會顯示任何內容。 10秒后,程序將終止。 讓我們添加一些日志記錄到控制台。
五、增加日志功能
LibLog可以配置為使用不同的日志框架; 即Log4Net,NLog和Serilog。
當LibLog沒有檢測到任何其他日志框架存在時,它將是不做任何事的。 如果您還沒有一個設置好的日志框架,我們可以配置一個自定義的日志記錄器提供程序,只需登錄到控制台即可顯示輸出。
1 LogProvider.SetCurrentLogProvider(new ConsoleLogProvider()); 2 3 private class ConsoleLogProvider : ILogProvider 4 { 5 public Logger GetLogger(string name) 6 { 7 return (level, func, exception, parameters) => 8 { 9 if (level >= LogLevel.Info && func != null) 10 { 11 Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters); 12 } 13 return true; 14 }; 15 } 16 17 public IDisposable OpenNestedContext(string message) 18 { 19 throw new NotImplementedException(); 20 } 21 22 public IDisposable OpenMappedContext(string key, string value) 23 { 24 throw new NotImplementedException(); 25 } 26 }
六、探索使用 Job 作業的完整過程
現在,當我們啟動應用程序時,我們應該獲得更多信息。
[10:52:50] [Info] Using object serializer: Quartz.Simpl.BinaryObjectSerializer, Quartz [10:52:50] [Info] Initialized Scheduler Signaller of type: Quartz.Core.SchedulerSignalerImpl [10:52:50] [Info] Quartz Scheduler v.3.0.7.0 created. [10:52:50] [Info] RAMJobStore initialized. [10:52:50] [Info] Scheduler meta-data: Quartz Scheduler (v3.0.7.0) 'QuartzScheduler' with instanceId 'NON_CLUSTERED' Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally. NOT STARTED. Currently in standby mode. Number of jobs executed: 0 Using thread pool 'Quartz.Simpl.DefaultThreadPool' - with 10 threads. Using job-store 'Quartz.Simpl.RAMJobStore' - which does not support persistence. and is not clustered. [10:52:50] [Info] Quartz scheduler 'QuartzScheduler' initialized [10:52:50] [Info] Quartz scheduler version: 3.0.7.0 [10:52:50] [Info] Scheduler QuartzScheduler_$_NON_CLUSTERED started.
我們需要一個簡單的測試工作來測試功能,讓我們創建HelloJob來向控制台輸出問候語。
1 public sealed class HelloJob : IJob 2 { 3 public async Task Execute(IJobExecutionContext context) 4 { 5 await Console.Out.WriteLineAsync("Greetings from HelloJob!"); 6 } 7 }
要做一些有趣的事情,您需要在Task.Delay之前的Start() 方法之后使用代碼。
1 // 定義job作業並將其綁定到HelloJob類 2 IJobDetail job = JobBuilder.Create<HelloJob>() 3 .WithIdentity("job1", "group1") 4 .Build(); 5 6 //觸發作業立即運行,然后每10秒重復一次 7 ITrigger trigger = TriggerBuilder.Create() 8 .WithIdentity("trigger1", "group1") 9 .StartNow() 10 .WithSimpleSchedule(x => x 11 .WithIntervalInSeconds(10) 12 .RepeatForever()) 13 .Build(); 14 15 //告訴 quartz 使用我們的觸發器安排作業 16 await scheduler.ScheduleJob(job, trigger);
完整的控制台應用程序現在看起來像這樣
1 using System; 2 using System.Threading.Tasks; 3 4 using Quartz; 5 using Quartz.Impl; 6 using Quartz.Logging; 7 8 namespace QuartzSampleApp 9 { 10 public class Program 11 { 12 private static void Main(string[] args) 13 { 14 LogProvider.SetCurrentLogProvider(new ConsoleLogProvider()); 15 16 RunProgram().GetAwaiter().GetResult(); 17 18 Console.WriteLine("Press any key to close the application"); 19 Console.ReadKey(); 20 } 21 22 private static async Task RunProgram() 23 { 24 try 25 { 26 // Grab the Scheduler instance from the Factory 27 NameValueCollection props = new NameValueCollection 28 { 29 { "quartz.serializer.type", "binary" } 30 }; 31 StdSchedulerFactory factory = new StdSchedulerFactory(props); 32 IScheduler scheduler = await factory.GetScheduler(); 33 34 // and start it off 35 await scheduler.Start(); 36 37 // define the job and tie it to our HelloJob class 38 IJobDetail job = JobBuilder.Create<HelloJob>() 39 .WithIdentity("job1", "group1") 40 .Build(); 41 42 // Trigger the job to run now, and then repeat every 10 seconds 43 ITrigger trigger = TriggerBuilder.Create() 44 .WithIdentity("trigger1", "group1") 45 .StartNow() 46 .WithSimpleSchedule(x => x 47 .WithIntervalInSeconds(10) 48 .RepeatForever()) 49 .Build(); 50 51 // Tell quartz to schedule the job using our trigger 52 await scheduler.ScheduleJob(job, trigger); 53 54 // some sleep to show what's happening 55 await Task.Delay(TimeSpan.FromSeconds(60)); 56 57 // and last shut down the scheduler when you are ready to close your program 58 await scheduler.Shutdown(); 59 } 60 catch (SchedulerException se) 61 { 62 Console.WriteLine(se); 63 } 64 } 65 66 // simple log provider to get something to the console 67 private class ConsoleLogProvider : ILogProvider 68 { 69 public Logger GetLogger(string name) 70 { 71 return (level, func, exception, parameters) => 72 { 73 if (level >= LogLevel.Info && func != null) 74 { 75 Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters); 76 } 77 return true; 78 }; 79 } 80 81 public IDisposable OpenNestedContext(string message) 82 { 83 throw new NotImplementedException(); 84 } 85 86 public IDisposable OpenMappedContext(string key, string value) 87 { 88 throw new NotImplementedException(); 89 } 90 } 91 } 92 93 public class HelloJob : IJob 94 { 95 public async Task Execute(IJobExecutionContext context) 96 { 97 await Console.Out.WriteLineAsync("Greetings from HelloJob!"); 98 } 99 } 100 }
現在去探索Quartz.NET吧! 您可以繼續閱讀本教程。原文地址如下:https://www.quartz-scheduler.net/documentation/quartz-3.x/quick-start.html