在.NET Core 中使用Quartz.NET
Quartz.NET是功能齊全的開源作業(yè)調(diào)度系統(tǒng),可用于最小的應(yīng)用程序到大型企業(yè)系統(tǒng)。
Quartz.NET具有三個(gè)主要概念:
?job:運(yùn)行的后臺(tái)任務(wù)?trigger:控制后臺(tái)任務(wù)運(yùn)行的觸發(fā)器。?scheduler:協(xié)調(diào)job和trigger
ASP.NET Core通過托管服務(wù)對(duì)運(yùn)行“后臺(tái)任務(wù)”具有良好的支持,托管服務(wù)在ASP.NET Core應(yīng)用程序啟動(dòng)時(shí)啟動(dòng),并在應(yīng)用程序生存期內(nèi)在后臺(tái)運(yùn)行,Quartz.NET版本3.2.0通過Quartz.Extensions.Hosting包引入了對(duì)該模式的直接支持,Quartz.Extensions.Hosting可以與ASP.NET Core應(yīng)用程序一起使用,也可以與基于“通用主機(jī)”的工作程序服務(wù)一起使用。
雖然.NET Core可以創(chuàng)建“定時(shí)”后臺(tái)服務(wù)(例如,每10分鐘運(yùn)行一次任務(wù)),但Quartz.NET提供了更為強(qiáng)大的解決方案, 通過使用Cron表達(dá)式,您可以確保任務(wù)在特定時(shí)間(例如,凌晨2:30)運(yùn)行,或僅在特定的幾天運(yùn)行,或這些時(shí)間的任意組合。Quartz.NET還允許您以集群方式運(yùn)行應(yīng)用程序的多個(gè)實(shí)例,以便在任何時(shí)候都只能運(yùn)行一個(gè)實(shí)例。
安裝Quartz.NET
Quartz.NET是一個(gè).NET Standard 2.0 NuGet軟件包,所以大部分項(xiàng)目都是支持的,你可以運(yùn)行安裝命令,dotnet add package Quartz.Extensions.Hosting,或者在NNuget可視化安裝,如果查看該項(xiàng)目的.csproj,應(yīng)該是下邊這樣:
<Project Sdk="Microsoft.NET.Sdk.Worker"><PropertyGroup><TargetFramework>net5.0</TargetFramework><UserSecretsId>dotnet-QuartzWorkerService-9D4BFFBE-BE06-4490-AE8B-8AF1466778FD</UserSecretsId></PropertyGroup><ItemGroup><PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" /><PackageReference Include="Quartz.Extensions.Hosting" Version="3.2.3" /></ItemGroup> </Project>安裝完成以后,這個(gè)包會(huì)自動(dòng)安裝 Quartz.NET包,接下來,我們需要在我們的應(yīng)用程序中注冊(cè)Quartz服務(wù)和Quartz 。
添加Quartz.NET hosted service
修改Program.cs,注冊(cè)服務(wù)
public class Program {public static void Main(string[] args){CreateHostBuilder(args).Build().Run();}public static IHostBuilder CreateHostBuilder(string[] args) =>Host.CreateDefaultBuilder(args).ConfigureServices((hostContext, services) =>{// Add the required Quartz.NET servicesservices.AddQuartz(q => {// Use a Scoped container to create jobs. I'll touch on this laterq.UseMicrosoftDependencyInjectionScopedJobFactory();});// Add the Quartz.NET hosted serviceservices.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);// other config}); }UseMicrosoftDependencyInjectionScopedJobFactory(),這個(gè)地方告訴Quartz.NET注冊(cè)一個(gè)IJobFactory,然后從DI容器中獲取Job,這樣也可以使用 Scoped 類型的服務(wù)。
WaitForJobsToComplete():當(dāng)程序關(guān)閉時(shí),此設(shè)置可確保Quartz.NET在退出之前等待Job正常結(jié)束。
如果現(xiàn)在運(yùn)行您的應(yīng)用程序,您將看到Quartz服務(wù)啟動(dòng),并將有很多日志輸出到控制臺(tái):
info: Quartz.Core.SchedulerSignalerImpl[0]Initialized Scheduler Signaller of type: Quartz.Core.SchedulerSignalerImpl info: Quartz.Core.QuartzScheduler[0]Quartz Scheduler v.3.2.3.0 created. info: Quartz.Core.QuartzScheduler[0]JobFactory set to: Quartz.Simpl.MicrosoftDependencyInjectionJobFactory info: Quartz.Simpl.RAMJobStore[0]RAMJobStore initialized. info: Quartz.Core.QuartzScheduler[0]Scheduler meta-data: Quartz Scheduler (v3.2.3.0) 'QuartzScheduler' with instanceId 'NON_CLUSTERED'Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally.NOT STARTED.Currently in standby mode.Number of jobs executed: 0Using thread pool 'Quartz.Simpl.DefaultThreadPool' - with 10 threads.Using job-store 'Quartz.Simpl.RAMJobStore' - which does not support persistence. and is not clustered.info: Quartz.Impl.StdSchedulerFactory[0]Quartz scheduler 'QuartzScheduler' initialized info: Quartz.Impl.StdSchedulerFactory[0]Quartz scheduler version: 3.2.3.0 info: Quartz.Core.QuartzScheduler[0]Scheduler QuartzScheduler_$_NON_CLUSTERED started. info: Microsoft.Hosting.Lifetime[0]Application started. Press Ctrl+C to shut down. ...現(xiàn)在,您已經(jīng)將Quartz作為托管服務(wù)運(yùn)行在您的應(yīng)用程序中,但是現(xiàn)在還沒有添加需要運(yùn)行的Job。
創(chuàng)建一個(gè)IJob
這個(gè)地方我創(chuàng)建一個(gè)簡(jiǎn)單的服務(wù),并且我可以從構(gòu)造函數(shù)中獲取服務(wù)。
using Microsoft.Extensions.Logging; using Quartz; using System.Threading.Tasks;[DisallowConcurrentExecution] public class HelloWorldJob : IJob {private readonly ILogger<HelloWorldJob> _logger;public HelloWorldJob(ILogger<HelloWorldJob> logger){_logger = logger;}public Task Execute(IJobExecutionContext context){_logger.LogInformation("Hello world!");return Task.CompletedTask;} }我還用[DisallowConcurrentExecution]特性,防止Quartz.NET嘗試同時(shí)運(yùn)行同一個(gè)作業(yè)。
設(shè)置Job
這個(gè)地方通常使用Cron表達(dá)式,來設(shè)置job的執(zhí)行時(shí)間。
public static IHostBuilder CreateHostBuilder(string[] args) =>Host.CreateDefaultBuilder(args).ConfigureServices((hostContext, services) =>{services.AddQuartz(q => {q.UseMicrosoftDependencyInjectionScopedJobFactory();// Create a "key" for the jobvar jobKey = new JobKey("HelloWorldJob");// Register the job with the DI containerq.AddJob<HelloWorldJob>(opts => opts.WithIdentity(jobKey));// Create a trigger for the jobq.AddTrigger(opts => opts.ForJob(jobKey) // link to the HelloWorldJob.WithIdentity("HelloWorldJob-trigger") // give the trigger a unique name.WithCronSchedule("0/5 * * * * ?")); // run every 5 seconds});services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);// ...});現(xiàn)在運(yùn)行應(yīng)用程序,您將看到和以前相同的啟動(dòng)消息,然后每隔5秒鐘就會(huì)看到HelloWorldJob寫入控制臺(tái)的信息:
將配置提取到appsettings.json
一般情況,我們都不會(huì)把cron表達(dá)式寫死在代碼中,一般是設(shè)置在appsettings.json中
{"Quartz": {"HelloWorldJob": "0/5 * * * * ?"} }為了更簡(jiǎn)單的注冊(cè)服務(wù),這個(gè)地方我簡(jiǎn)單做了一個(gè)封裝,這樣也更靈活。
public static class ServiceCollectionQuartzConfiguratorExtensions {public static void AddJobAndTrigger<T>(this IServiceCollectionQuartzConfigurator quartz,IConfiguration config)where T : IJob{// Use the name of the IJob as the appsettings.json keystring jobName = typeof(T).Name;// Try and load the schedule from configurationvar configKey = $"Quartz:{jobName}";var cronSchedule = config[configKey];// Some minor validationif (string.IsNullOrEmpty(cronSchedule)){throw new Exception($"No Quartz.NET Cron schedule found for job in configuration at {configKey}");}// register the job as beforevar jobKey = new JobKey(jobName);quartz.AddJob<T>(opts => opts.WithIdentity(jobKey));quartz.AddTrigger(opts => opts.ForJob(jobKey).WithIdentity(jobName + "-trigger").WithCronSchedule(cronSchedule)); // use the schedule from configuration} }然后修改Program.cs,然后使用擴(kuò)展方法:
public class Program {public static void Main(string[] args) => CreateHostBuilder(args).Build().Run();public static IHostBuilder CreateHostBuilder(string[] args) =>Host.CreateDefaultBuilder(args).ConfigureServices((hostContext, services) =>{services.AddQuartz(q =>{q.UseMicrosoftDependencyInjectionScopedJobFactory();// Register the job, loading the schedule from configurationq.AddJobAndTrigger<HelloWorldJob>(hostContext.Configuration);});services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);}); }再次運(yùn)行該應(yīng)用程序?qū)⑻峁┫嗤妮敵?#xff1a;Job每5秒輸入一次信息。
原文作者: andrewlock?
原文鏈接:?https://andrewlock.net/using-quartz-net-with-asp-net-core-and-worker-services/[1]
最后
歡迎掃碼關(guān)注我們的公眾號(hào) 【全球技術(shù)精選】,專注國(guó)外優(yōu)秀博客的翻譯和開源項(xiàng)目分享,也可以添加QQ群 897216102
References
[1]?https://andrewlock.net/using-quartz-net-with-asp-net-core-and-worker-services/:?"https://andrewlock.net/using-quartz-net-with-asp-net-core-and-worker-services/"
總結(jié)
以上是生活随笔為你收集整理的在.NET Core 中使用Quartz.NET的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在 ASP.Net Core 使用
- 下一篇: EntityFramework Core