現在有了一個官方包Quartz.Extensions.Hosting實現使用Quartz.Net運行后台任務,所以把Quartz.Net添加到ASP.NET Core或Worker Service要簡單得多。
我將展示如何把Quartz.Net HostedService添加到你的應用,如何創建一個簡單的IJob,以及如何注冊它與trigger。
簡介——什么是Quartz.Net
Quartz.Net是一個功能齊全的開源作業調度系統,可以在最小規模的應用程序到大型企業系統使用。
有許多ASP.NET的釘子戶,他們以一種可靠的、集群的方式在定時器上運行后台任務。使用在ASP.NET Core中使用的Quartz.Net支持了.NET Standar 2.0,因此你可以輕松地在應用程序中使用它。
Quartz.Net有三個主要概念:
- job。這是你想要運行的后台任務。
- trigger。trigger控制job何時運行,通常按某種調度規則觸發。
- scheduler。它負責協調job和trigger,根據trigger的要求執行job。
ASP.NET Core很好地支持通過hosted services(托管服務)運行“后台任務”。當你的ASP.NET Core應用程序啟動,托管服務也啟動,並在應用程序的生命周期中在后台運行。Quartz.Net 3.2.0通過Quartz.Extensions.Hosting引入了對該模式的直接支持。Quartz.Extensions.Hosting即可以用在ASP.NET Core應用程序,也可以用在基於“通用主機”的Worker Service。
雖然可以創建一個“定時”后台服務(例如,每10分鍾運行一個任務),但Quartz.NET提供了一個更加健壯的解決方案。通過使用Cron trigger,你可以確保任務只在一天的特定時間(例如凌晨2:30)運行,或者只在特定的日子運行,或者這些時間的任意組合運行。Quartz.Net還允許你以集群的方式運行應用程序的多個實例,以便在任何時候只有一個實例可以運行給定的任務。
Quartz.Net托管服務負責Quartz的調度。它將在應用程序的后台運行,檢查正在執行的觸發器,並在必要時運行相關的作業。你需要配置調度程序,但不需要擔心啟動或停止它,IHostedService會為你管理。
在這篇文章中,我將展示創建Quartz.Net job的基礎知識。並將其調度到托管服務中的定時器上運行。
安裝Quartz.Net
Quartz.Net是一個.NET Standar 2.0的NuGet包,所以它很容易安裝在你的應用程序中。對於這個測試,我創建了一個Worker Service項目。你可以通過使用dotnet add package Quartz.Extensions.Hosting命令安裝Quartz.Net托管包。如果你查看項目的.csproj,它應該是這樣的:
這將添加托管服務包,從而引入Quartz.Net。接下來,我們需要在應用程序中注冊Quartz.Net的服務和 IHostedService。
添加Quartz.Net托管服務
注冊Quartz.Net需要做兩件事:
- 注冊Quartz.Net需要的DI容器服務。
- 注冊托管服務。
在ASP.NET Core中,通常會在Startup.ConfigureServices()方法中完成這兩項操作。Worker Services不使用Startup類,所以我們在Program.cs中的IHostBuilder的ConfigureServices方法中注冊它們:
- UseMicrosoftDependencyInjectionScopedJobFactory:它告訴Quartz.NET注冊一個IJobFactory,該IJobFactory通過從DI容器中創建job。方法中的Scoped部分意味着你的作業可以使用scoped服務,而不僅僅是single或transient服務。
- WaitForJobsToComplete:此設置確保當請求關閉時,Quartz.NET在退出之前等待作業優雅地結束。
如果你現在運行應用程序,將看到Quartz服務啟動,並將大量日志轉儲到控制台:
此時,你已經讓Quartz作為托管服務在你的應用程序中運行,但是沒有任何job讓它運行。在下一節中,我們將創建並注冊一個簡單的job。
創建job
對於我們正在調度的實際后台工作,我們將使用一個"hello world"實現它寫入一個ILogger<T>。你應該實現Quartz.NET的接口IJob,它包含一個異步的Execute()方法。注意,我們在這里使用依賴注入將日志程序注入到構造函數中。
我還用[DisallowConcurrentExecution]屬性裝飾了job。此屬性防止Quartz.NET試圖同時運行相同的作業。
現在我們已經創建了作業,我們需要將它與trigger一起注冊到DI容器中。
配置job
Quartz.NET為運行job提供了一些簡單的schedule,但最常見的方法之一是使用Quartz.NET Cron表達式。Cron表達式允許復雜的計時器調度,所以你可以設置規則,比如“每個月的5號和20號,在早上8點到10點之間每半小時觸發一次”。使用時請確保檢查示例文檔,因為不同系統使用的所有Cron表達式都是可互換的。
下面的示例展示了如何使用每5秒運行一次的trggier來注冊HelloWorldJob:
- 為job創建唯一的JobKey。這用於將job與其trggier連接在一起。還有其他連接job和trggier的方法,但我認為這和其他方法一樣好。
- 用AddJob<T>注冊HelloWorldJob。這做了兩件事—它將HelloWorldJob添加到DI容器中,這樣就可以創建它;它在內部向Quartz注冊job。
- 添加一個觸發器,每5秒運行一次作業。我們使用JobKey將trigger與一個job關聯起來,並為trigger提供唯一的名稱(在本例中不是必需的,但如果你在集群模式下運行quartz,這很重要)。最后,我們為trigger設置了Cron調度,使作業每5秒運行一次。
這就實現了功能!不再需要創建自定義的IJobFactory,也不用擔心是否支持scoped的服務。
默認的包為你處理所有這些問題——你可以在IJob中使用scoped的服務,它們將在job完成時被刪除。
如果你現在運行你的應用程序,你會看到和以前一樣的啟動消息,然后每5秒你會看到HelloWorldJob寫入控制台:
這就是啟動和運行所需的全部內容,但是根據我的喜好,在ConfigureServices方法中添加了太多內容。你也不太可能想在應用程序中硬編碼作業調度。例如,如果將其提取到配置中,可以在每個環境中使用不同的調度。
最起碼,我們希望將Cron調度提取到配置中。例如,你可以在appsettings.json中添加以下內容:
{ "Quartz": { "HelloWorldJob": "0/5 * * * * ?" } }
然后,你可以輕松地在不同環境中覆蓋HelloWorldJob的觸發器調度。
為了方便注冊,我們可以創建一個擴展方法來封裝在Quartz上注冊IJob,並設置它的trigger調度。這段代碼與前面的示例基本相同,但是它使用job的名稱在IConfiguration中加載Cron調度。
再次運行應用程序會給出相同的輸出:job每5秒寫一次輸出。
總結
在這篇文章中,我介紹了Quartz.NET並展示了如何使用新的Quartz.Extensions.Hosting輕松添加一個ASP.NET Core托管服務運行Quartz調度器。我展示了如何使用trigger實現一個簡單的job,以及如何將其注冊到應用程序中,以便托管的服務按計划運行它。
歡迎關注我的公眾號,如果你有喜歡的外文技術文章,可以通過公眾號留言推薦給我。
原文鏈接:https://andrewlock.net/using-quartz-net-with-asp-net-core-and-worker-services/