<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í)行任務調度

          共 7106字,需瀏覽 15分鐘

           ·

          2020-12-19 13:21


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

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

          安裝 Quartz.NET

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


          Install-Package?Quartz

          Quartz.NET 中的Job,triggers 和 Schedulers

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


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

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

          Scheduler 通常按照你預先設置的調度規(guī)則將 job 丟給它的任務隊列,并按照 trigger 規(guī)則輪詢然后執(zhí)行任務。

          創(chuàng)建 Scheduler

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


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

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


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

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

          開啟和停止 scheduler

          為了方便實現?開啟?和?停止?功能,我準備封裝一個 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?中,實現代碼如下:


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

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

          創(chuàng)建 job

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

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


          ????[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 工廠,則必須要實現 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)?{?}
          ????}

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

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

          我準備定義一個 JobMetadata 類去存儲和job 相關聯的元數據,比如說: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();
          }???

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

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

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



          往期精彩回顧




          【推薦】.NET Core開發(fā)實戰(zhàn)視頻課程?★★★

          .NET Core實戰(zhàn)項目之CMS 第一章 入門篇-開篇及總體規(guī)劃

          【.NET Core微服務實戰(zhàn)-統一身份認證】開篇及目錄索引

          Redis基本使用及百億數據量中的使用技巧分享(附視頻地址及觀看指南)

          .NET Core中的一個接口多種實現的依賴注入與動態(tài)選擇看這篇就夠了

          10個小技巧助您寫出高性能的ASP.NET Core代碼

          用abp vNext快速開發(fā)Quartz.NET定時任務管理界面

          在ASP.NET Core中創(chuàng)建基于Quartz.NET托管服務輕松實現作業(yè)調度

          現身說法:實際業(yè)務出發(fā)分析百億數據量下的多表查詢優(yōu)化

          關于C#異步編程你應該了解的幾點建議

          C#異步編程看這篇就夠了


          瀏覽 65
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  久久国产精品视频 | 中文字幕东京热 | 78m成人视频中文音声 | 国产精品天干综合 | 97国产成人无码精品久久久 |