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(); }