.Net Core 之 (Hangfire 和 Quertz)定時任務

Hangfire 

 

用法比較簡單,也直接去官網看。這裏直接說幾種模式的用法。

項目示例

準備工作

1. 引入nuget包

Hangfire.AspNetCore

Hangfire.Dashboard.BasicAuthorization  #用於Dashboard面板

Hangfire.SqlServer  #我這裏用的sqlserver,如果用其他的數據庫存儲就換成對應的擴展包

2. appsettings.json中添加配置

  "HangfireConfig": {
    "SslRedirect": false,
    "RequireSsl": false,
    "LoginCaseSensitive": false,
    "Login": "fcbadmin",
    "PasswordClear": "123456",
    "ConnectionString": "Server=.\\sqlexpress;Database=HangfireTest;Integrated Security=SSPI;"
  }

3.  Program中添加服務注入配置

builder.Services.AddHangfire(configuration => configuration
       //.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
       .UseSimpleAssemblyNameTypeSerializer()
       .UseRecommendedSerializerSettings()
       .UseSqlServerStorage(builder.Configuration.GetSection("HangfireConfig:ConnectionString").Value, new SqlServerStorageOptions
       {
           CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
           SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
           QueuePollInterval = TimeSpan.Zero,
           UseRecommendedIsolationLevel = true,
           DisableGlobalLocks = true
       }));
builder.Services.AddHangfireServer();

或者換種簡單的

builder.Services.AddHangfire(config =>
{
    config.UseStorage(new SqlServerStorage(Configuration.GetSection("HangfireConfig").GetValue<string>("ConnectionString")));
});

4. Program中添加Dashboard面板,這裏添加了賬號認證,如果覺得沒有必要把配置取消就可以了

app.UseHangfireDashboard("/task", new DashboardOptions
{
    Authorization = new[] {
                    new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions{

                         SslRedirect = builder.Configuration.GetSection("HangfireConfig").GetValue<bool>("SslRedirect"),
                         RequireSsl=builder.Configuration.GetSection("HangfireConfig").GetValue<bool>("RequireSsl"),
                         LoginCaseSensitive=builder.Configuration.GetSection("HangfireConfig").GetValue<bool>("LoginCaseSensitive"),
                         Users=new []{
                             new BasicAuthAuthorizationUser{
                                 Login=builder.Configuration.GetSection("HangfireConfig").GetValue<string>("Login"),
                                 PasswordClear=builder.Configuration.GetSection("HangfireConfig").GetValue<string>("PasswordClear")
                             }
                         }
                    })
                },
});

準備工作完成了,下面就看幾種模式用法

定時任務

        /// <summary>
        /// 執行定時任務。定期作業按指定的 CRON 計劃觸發多次。
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("Test_RecurringJob")]
        public async Task<IActionResult> Test_RecurringJob()
        {
            //自動獲取本地時區
            RecurringJob.AddOrUpdate<ValuesController>("測試定時任務", x => x.TestRecurringJobContent(), Cron.MinuteInterval(10), TimeZoneInfo.Local);

            ////指定Windows時區
            //RecurringJob.AddOrUpdate<ValuesController>("測試定時任務", x =>  x.TestRecurringJobContent(), Cron.MinuteInterval(2), TimeZoneInfo.CreateCustomTimeZone("China Standard Time", new TimeSpan(08, 00, 00), "China Standard Time", "China Standard Time"));

            ////指定Linux時區
            //RecurringJob.AddOrUpdate<ValuesController>("測試定時任務", x => x.TestRecurringJobContent(), Cron.MinuteInterval(2), TimeZoneInfo.CreateCustomTimeZone("Asia/Shanghai", new TimeSpan(08, 00, 00), "Asia/Shanghai", "Asia/Shanghai"));
            return Ok("執行成功");
        }
        /// <summary>
        /// 執行定時任務
        /// </summary>
        /// <returns></returns>
        public async Task<IActionResult> TestRecurringJobContent()
        {
            Console.WriteLine("執行了定時任務");
            return Ok();
        }     

一次性作業

        /// <summary>
        /// 立即執行一次性作業。即發即棄作業僅在創建後立即執行一次。
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("Test_BackgroundJob_Enqueue")]
        public async Task<IActionResult> Test_BackgroundJob_Enqueue()
        {
            var jobId = BackgroundJob.Enqueue(
                    () => Console.WriteLine("執行了立即執行一次性作業"));
            return Ok("執行成功");
        }  

延遲作業

        /// <summary>
        /// 延遲作業。延遲的作業也只執行一次,但不會在一定時間間隔後立即執行。
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("Test_BackgroundJob_Schedule")]
        public async Task<IActionResult> Test_BackgroundJob_Schedule()
        {
            var jobId = BackgroundJob.Schedule(
                    () => Console.WriteLine("執行了延遲作業"),
                    TimeSpan.FromMinutes(1));
            return Ok("執行成功");
        }

延續作業  

        /// <summary>
        /// 延續作業。延續在其父作業完成時執行。
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("Test_BackgroundJob_ContinueJobWith")]
        public async Task<IActionResult> Test_BackgroundJob_ContinueJobWith()
        {
            Console.WriteLine("開始等待,當前時間:" + DateTime.Now);
            var jobId = BackgroundJob.Schedule(
                    () => Console.WriteLine("執行了2秒延遲作業,當前時間:"+DateTime.Now),
                    TimeSpan.FromSeconds(2));
            BackgroundJob.ContinueJobWith(
             jobId,
             () => Console.WriteLine("在執行了2秒延遲作業之後,又執行了延續作業,當前時間:" + DateTime.Now));
            return Ok("執行成功");
        }

 

Quartz

Quartz.Net 官網:https://www.quartz-scheduler.net/

個人感覺沒有hangfire好用,使用要稍微複雜一些,官方沒有看到類似於hangfire中Dashboard的可視化界面,網上倒是很多人擴展了,可以直接用

核心接口

Scheduler - 與調度程序交互的主要API。
Job - 你想要調度器執行的任務組件需要實現的接口
JobDetail - 用於定義作業的實例。
Trigger(即觸發器) - 定義執行給定作業的計劃的組件。
JobBuilder - 用於定義/構建 JobDetail 實例,用於定義作業的實例。
TriggerBuilder - 用於定義/構建觸發器實例。
Scheduler 的生命期,從 SchedulerFactory 創建它時開始,到 Scheduler 調用shutdown() 方法時結束;Scheduler 被創建後,可以增加、刪除和列舉 Job 和 Trigger,以及執行其它與調度相關的操作(如暫停 Trigger)。但是,Scheduler 只有在調用 start() 方法後,纔會真正地觸發 trigger(即執行 job)

準備工作

1. 引入nuget包

Quartz

2.  Program中添加服務注入配置,這裏沒有集成數據庫

builder.Services.AddScoped<ISchedulerFactory, StdSchedulerFactory>();

 

3. api中依賴注入

private readonly ISchedulerFactory _schedulerFactory;
        private readonly IScheduler _scheduler;
       
        public ValuesController( ISchedulerFactory schedulerFactory)
        {
            _schedulerFactory = schedulerFactory;
            _scheduler = _schedulerFactory.GetScheduler().Result;  //通過工場類獲得調度器
        }

簡單使用

      public async Task<IActionResult> RecurringJob()
      {
          //開啓調度器
          await _scheduler.Start();
          //創建觸發器(也叫時間策略)
          var trigger = TriggerBuilder.Create()
                          // .WithSimpleSchedule(x => x.WithIntervalInMinutes(1).RepeatForever())//每分鐘執行一次,一直重複執行
                          //.WithSimpleSchedule(x => x.WithIntervalInSeconds(2).WithRepeatCount(5))//每2秒執行一次,重複執行五次
                          .WithCronSchedule("0/2 * * * * ?")  //使用cron指定運行時間來執行,每2秒運行一次
                         // .WithIdentity("fcbjob","fcbgroup") 
                          .Build();
          //創建作業實例
          //Jobs即我們需要執行的作業
          var jobDetail = JobBuilder.Create<FCBJob>()
                          .WithIdentity("Myjob", "fcbgroup")//我們給這個作業取了個“Myjob”的名字,取了個組名爲“fcbgroup”,這裏會通過這兩個名字來生成唯一的jobkey,如果不指定會默認生成一個唯一jobkey
                          .Build();

          await _scheduler.ScheduleJob(jobDetail, trigger);
          return Ok("執行成功");
      }

一個Job執行多個觸發器

job和trigger 可以是一對多的關係

       public async Task<IActionResult> RecurringJobs()
       {
           //開啓調度器
           await _scheduler.Start();
           //創建觸發器(也叫時間策略)
           var trigger = TriggerBuilder.Create()
                           .WithCronSchedule("0/2 * * * * ?")  //使用cron指定運行時間來執行,每2秒運行一次
                           .WithIdentity("fcbjob","fcbgroup") 
                           .Build();

           var trigger2 = TriggerBuilder.Create()
                         .WithCronSchedule("0/1 * * * * ?")  //使用cron指定運行時間來執行,每2秒運行一次
                         .WithIdentity("fcbjob2", "fcbgroup")
                         .Build();

           var jobDetail2 = JobBuilder.Create<FCBJob2>()
                           .WithIdentity("Myjob2", "fcbgroup")
                           .Build();
           Dictionary<IJobDetail, IReadOnlyCollection<ITrigger>> keyValuePairs = new Dictionary<IJobDetail, IReadOnlyCollection<ITrigger>>();
           keyValuePairs.Add(jobDetail2, new List<ITrigger>() {
               trigger,trigger2
           });
           await _scheduler.ScheduleJobs(keyValuePairs,true);
           return Ok("執行成功");
       }

停止任務調度

public async Task<IActionResult> ShutdownScheduler()
{
  await _scheduler.Shutdown();
  return Ok(); 
}

暫停定時任務

   public async Task<IActionResult> PauseJob()
   {
       //暫停job
       //JobKey jobKey = new JobKey("Myjob", "fcbgroup");
       //if (await _scheduler.CheckExists(jobKey))
       //{
       //    await _scheduler.PauseJob(jobKey);
       //}

       //暫停triggerKey
       TriggerKey triggerKey = new TriggerKey("fcbjob", "fcbgroup");
       if (await _scheduler.CheckExists(triggerKey))
       {
           await _scheduler.PauseTrigger(triggerKey);
       }
       return Ok();
   }

恢復定時任務

   public async Task<IActionResult> ResumeJob()
   {
       //恢復job
       //JobKey jobKey = new JobKey("Myjob", "fcbgroup");
       //if (await _scheduler.CheckExists(jobKey))
       //{
       //    await _scheduler.ResumeJob(jobKey);
       //}

       //恢復triggerKey
       TriggerKey triggerKey = new TriggerKey("fcbjob", "fcbgroup");
       if (await _scheduler.CheckExists(triggerKey))
       {
           await _scheduler.ResumeTrigger(triggerKey);
       }
       return Ok();
   }

刪除定時任務

    public async Task<IActionResult> DeleteJob()
    {
        JobKey jobKey = new JobKey("Myjob", "fcbgroup");
        if (await _scheduler.CheckExists(jobKey))
        {
            await _scheduler.DeleteJob(jobKey);
        }
        return Ok();
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章