<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何在 ASP.NET Core 中使用 Quartz.NET 執(zhí)行任務(wù)調(diào)度

          共 6794字,需瀏覽 14分鐘

           ·

          2021-01-19 04:02

          當(dāng)我們在web開發(fā)中,常常會遇到這么一個需求,在后臺執(zhí)行某一項具體的任務(wù),具體的說就是這些任務(wù)必須在后臺定時執(zhí)行。

          Quartz.NET 是一個開源的 JAVA 移植版,它有著悠久的歷史并且提供了強大的 Cron 表達(dá)式,這篇我們就來討論如何在 ASP.NET Core 中使用 Quartz.NET 去執(zhí)行一些后臺任務(wù)。

          安裝 Quartz.NET

          要想使用 Quartz.NET,你可以使用 Visual Studio 2019 中的 NuGet package manager 可視化界面進(jìn)行安裝,或者通過 NuGet package manager console 命令行輸入如下命令:


          Install-Package?Quartz

          Quartz.NET 中的Job,triggers 和 Schedulers

          Quartz.NET 里有三個非常重要的概念:任務(wù),觸發(fā)器 和 調(diào)度器,對應(yīng)著 Job,Trigger 和 Schedulers,Job 表示一個你需要被執(zhí)行的任務(wù),任務(wù)中可以寫上你的業(yè)務(wù)邏輯代碼,Job 就是一個實現(xiàn)了 IJob 接口的子類,如下代碼所示:


          ????class?Job?:?IJob
          ????{
          ????????public?Task?Execute(IJobExecutionContext?context)
          ????????{
          ????????????throw?new?NotImplementedException();
          ????????}
          ????}

          Trigger 通常用于指定一個 job 是如何被調(diào)度的?什么意思呢?比如說:這個job是按天執(zhí)行?還是按小時執(zhí)行?還是按秒執(zhí)行?值得注意的是因為支持了 Cron 表達(dá)式,還能夠?qū)崿F(xiàn)更加超級復(fù)雜的調(diào)度邏輯。

          Scheduler 通常按照你預(yù)先設(shè)置的調(diào)度規(guī)則將 job 丟給它的任務(wù)隊列,并按照 trigger 規(guī)則輪詢?nèi)缓髨?zhí)行任務(wù)。

          創(chuàng)建 Scheduler

          在 Quartz.NET 中可以創(chuàng)建多個 Scheduler,但為了演示目的我就創(chuàng)建一個 Scheduler 啦,下面的代碼展示了如何去創(chuàng)建 Scheduler。


          var?scheduler?=?StdSchedulerFactory.GetDefaultScheduler().GetAwaiter().GetResult();

          一旦使用上面的代碼創(chuàng)建好了 Scheduler,接下來就可以將其作為服務(wù)注入到 Asp.net Core 的 IOC 容器中,實現(xiàn)代碼如下:


          ????????public?void?ConfigureServices(IServiceCollection?services)
          ????????{
          ????????????var?scheduler?=?StdSchedulerFactory.GetDefaultScheduler().GetAwaiter().GetResult();

          ????????????services.AddSingleton(scheduler);
          ????????????services.AddRazorPages();
          ????????}

          開啟和停止 scheduler

          為了方便實現(xiàn) 開啟停止 功能,我準(zhǔn)備封裝一個 hosting service 類,做法就是從 IHostingService 接口派生出一個 CustomQuartzHostedService 類,完整代碼如下:


          public?class?CustomQuartzHostedService?:?IHostedService
          {
          ????????private?readonly?IScheduler?_scheduler;
          ????????public?CustomQuartzHostedService(IScheduler?scheduler)
          ????????{
          ????????????_scheduler?=?scheduler;
          ????????}
          ????????public?async?Task?StartAsync(CancellationToken?cancellationToken)
          ????????{
          ????????????await?_scheduler?.Start(cancellationToken);
          ????????}
          ????????public?async?Task?StopAsync(CancellationToken?cancellationToken)
          ????????{
          ????????????await?_scheduler?.Shutdown(cancellationToken);
          ????????}
          ?}

          有了這個自定義類,接下來把這個類也注入到 servcies collection 中,實現(xiàn)代碼如下:


          ????????public?void?ConfigureServices(IServiceCollection?services)
          ????????{
          ????????????var?scheduler?=?StdSchedulerFactory.GetDefaultScheduler().GetAwaiter().GetResult();

          ????????????services.AddSingleton(scheduler);
          ????????????services.AddHostedService();
          ????????????services.AddRazorPages();
          ????????}

          創(chuàng)建 job

          正如之前說到的,job 是一個實現(xiàn)了 IJob 接口 并且實現(xiàn)了 Execute() 的類,這個 Execute() 方法接收一個 IJobExecutionContext 參數(shù)。

          下面的代碼片段展示了這個 Job 類包含了一個異步方式的 Execute() 方法,這個方法中包含的代碼就是你需要執(zhí)行的業(yè)務(wù)邏輯。


          ????[DisallowConcurrentExecution]
          ????public?class?NotificationJob?:?IJob
          ????{
          ????????private?readonly?ILogger?_logger;
          ????????public?NotificationJob(ILogger?logger)
          ????????{
          ????????????_logger?=?logger;
          ????????}
          ????????public?Task?Execute(IJobExecutionContext?context)
          ????????{
          ????????????_logger.LogInformation("Hello?world!");
          ????????????return?Task.CompletedTask;
          ????????}
          ????}

          創(chuàng)建 job 工廠

          如果要定義一個 Job 工廠,則必須要實現(xiàn) IJobFactory 接口中的 NewJob() 和 ReturnJob() 方法,下面的代碼片段展示了如何去 創(chuàng)建 和 返回 job 的 factory 類。


          ????public?class?CustomQuartzJobFactory?:?IJobFactory
          ????{
          ????????private?readonly?IServiceProvider?_serviceProvider;
          ????????public?CustomQuartzJobFactory(IServiceProvider?serviceProvider)
          ????????{
          ????????????_serviceProvider?=?serviceProvider;
          ????????}
          ????????public?IJob?NewJob(TriggerFiredBundle?triggerFiredBundle,
          ????????IScheduler?scheduler
          )

          ????????{
          ????????????var?jobDetail?=?triggerFiredBundle.JobDetail;
          ????????????return?(IJob)_serviceProvider.GetService(jobDetail.JobType);
          ????????}
          ????????public?void?ReturnJob(IJob?job)?{?}
          ????}

          值得注意的是,這里我并沒有實現(xiàn) job 池,如果你想實現(xiàn)這個功能,你需要修改以下 NewJob() 方法 并且重寫 ReturnJob() 方法。

          創(chuàng)建 JobMetadata 存儲你的 job 元數(shù)據(jù)

          我準(zhǔn)備定義一個 JobMetadata 類去存儲和job 相關(guān)聯(lián)的元數(shù)據(jù),比如說:job的id,job的name 等等,下面的代碼展示了如何定義這么一個類。


          ????public?class?JobMetadata
          ????{
          ????????public?Guid?JobId?{?get;?set;?}
          ????????public?Type?JobType?{?get;?}
          ????????public?string?JobName?{?get;?}
          ????????public?string?CronExpression?{?get;?}
          ????????public?JobMetadata(Guid?Id,?Type?jobType,?string?jobName,
          ????????string?cronExpression
          )

          ????????{
          ????????????JobId?=?Id;
          ????????????JobType?=?jobType;
          ????????????JobName?=?jobName;
          ????????????CronExpression?=?cronExpression;
          ????????}
          ????}

          使用 hosted service 封裝 Scheduler 的start和stop

          接下來,我需要豐富一下 CustomQuartzHostedService 類,完整的代碼清單如下。


          ????public?class?CustomQuartzHostedService?:?IHostedService
          ????{
          ????????private?readonly?ISchedulerFactory?schedulerFactory;
          ????????private?readonly?IJobFactory?jobFactory;
          ????????private?readonly?JobMetadata?jobMetadata;
          ????????public?CustomQuartzHostedService(ISchedulerFactory?schedulerFactory,JobMetadata?jobMetadata,IJobFactory?jobFactory)
          ????????{
          ????????????this.schedulerFactory?=?schedulerFactory;
          ????????????this.jobMetadata?=?jobMetadata;
          ????????????this.jobFactory?=?jobFactory;
          ????????}
          ????????public?IScheduler?Scheduler?{?get;?set;?}
          ????????public?async?Task?StartAsync(CancellationToken?cancellationToken)
          ????????{
          ????????????Scheduler?=?await?schedulerFactory.GetScheduler();
          ????????????Scheduler.JobFactory?=?jobFactory;
          ????????????var?job?=?CreateJob(jobMetadata);
          ????????????var?trigger?=?CreateTrigger(jobMetadata);
          ????????????await?Scheduler.ScheduleJob(job,?trigger,?cancellationToken);
          ????????????await?Scheduler.Start(cancellationToken);
          ????????}
          ????????public?async?Task?StopAsync(CancellationToken?cancellationToken)
          ????????{
          ????????????await?Scheduler?.Shutdown(cancellationToken);
          ????????}
          ????????private?ITrigger?CreateTrigger(JobMetadata?jobMetadata)
          ????????{
          ????????????return?TriggerBuilder.Create()
          ?????????????????????????????????.WithIdentity(jobMetadata.JobId.ToString())
          ?????????????????????????????????.WithCronSchedule(jobMetadata.CronExpression)
          ?????????????????????????????????.WithDescription($"{jobMetadata.JobName}")
          ?????????????????????????????????.Build();
          ????????}
          ????????private?IJobDetail?CreateJob(JobMetadata?jobMetadata)
          ????????{
          ????????????return?JobBuilder
          ????????????.Create(jobMetadata.JobType)
          ????????????.WithIdentity(jobMetadata.JobId.ToString())
          ????????????.WithDescription($"{jobMetadata.JobName}")
          ????????????.Build();
          ????????}
          ????}

          接下來再看一下 ?Startup.ConfigureServices 方法下的完整代碼。


          public?void?ConfigureServices(IServiceCollection?services)
          {
          ????services.AddRazorPages();
          ????services.AddSingleton();
          ????services.AddSingleton();
          ????services.AddSingleton();
          ????services.AddSingleton(new?JobMetadata(Guid.NewGuid(),?typeof(NotificationJob),"Notification?Job",?"0/10?*?*?*?*??"));
          ????services.AddHostedService();
          }???

          這就是所有要做的事情,接下來運行應(yīng)用程序,你會觀察到 NotificationJob 的 Execute() 方法會每 10s 執(zhí)行一次。

          如何你的應(yīng)用程序中需要有任務(wù)調(diào)用的功能,現(xiàn)在開始可以不需要使用Timer了,采用強大的 Quartz.NET 即可,而且還有一個????的功能就是:你可以把 job 持久化到 SQL Server, PostgreSQL, SQLite 中,太強大了。

          譯文鏈接:https://www.infoworld.com/article/3529418/how-to-schedule-jobs-using-quartznet-in-aspnet-core.html


          瀏覽 56
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天搡天天狠天干天啪 | 波多野结衣在线不卡 | 成人网站在线观看18 | 在线国产三级 | 国产综合17网在线 |