注意:
1. 當Hangfire服務由Web程序來啟用時,默認情況下,web應用程序中的Hangfire服務器實例在第一個用戶訪問您的站點之前不會啟動。甚至,有一些事件會在一段時間后導致web應用程序關閉(比如空閑超時應用程序池回收事件)。在這些情況下, “循環任務”和“延遲作業”將不會進入隊列,而“進入隊列的作業”將不會被處理。因此我們需要讓ASP.NET應用程序始終運行。(詳見官方的方法:Making ASP.NET application always running)
2. Hangfire Dashboard是一個你可以找到所有關於你的后台工作的信息的地方。它是作為一個OWIN中間件編寫的(如果你不熟悉OWIN,也不用擔心),所以你可以將它插入到你的 ASP.NET, ASP.NET MVC, Nancy, ServiceStack應用程序中,以及使用OWIN Self-Host 功能,在控制台應用程序或在Windows服務中托管Hangfire Dashboard服務。(詳見官方說明: Using Dashboard)
前言:
定時任務調度問題,是一個老生常談的問題。網上有許多定時任務調度的解決方案,對於我而言很早以前主要是使用Window計划和Window服務來做任務定時執行,然后就開始使用定時任務調度框架Quartz.Net。但是卻一直沒有上手過Hangfire這個自帶后台任務調度面板,可以在后台手動執行任務的神奇的任務調度框架。前段時間終於開始對他下手了,通過在網上查閱了一些資料和查看了Hangfire在Github中的demo,終於在我自己的項目中用上了Hangfire。在該篇文章中主要簡單介紹一下什么是Hangfire,Hangfire的基本特征與優點和分別使用MySQL,MS SQL Server作為存儲使用。
一、Hangfire是什么:
hangfire官網https://www.hangfire.io/
Hangfire是一個開源的.NET任務調度框架,提供了內置集成化的控制台,可以直觀明了的查看作業調度情況,並且Hangfire不需要依賴於單獨的應用程序執行(如:windows服務,window計划)。並且支持持久性存儲。
二、Hangfire使用條件:
Hangfire與特定的.NET應用程序類型無關。您可以在ASP.NET Web應用程序,非ASP.NET Web應用程序,控制台應用程序或Windows服務中使用它。以下是要求:
1.NET Framework 4.5
2.永久存儲(Hangfire將后台作業和其他與處理有關的信息保留在永久性存儲器中,所以需要存儲庫來存儲如:MS SQL Server,Redis,MySQL,PostgreSql等)
3.Newtonsoft.Json庫≥5.0.1
三、Hangfire安裝和使用:
第一步:創建WebApi項目承載任務調度
在ASP.NET 應用程序下使用Hangfire安裝:
Install-Package Hangfire (SQlServer內置)
使用mysql作為存儲時我們需要安裝的NuGet:
Install-Package Hangfire.MySql.Core
修改appsettings.json配置文件,添加持久化作業數據的數據庫連接
<connectionStrings> <add name="sqlserver_connection" connectionString="Data Source=.;Initial Catalog=MyFirstDb;Integrated Security=True" providerName="System.Data.SqlClient" /> </connectionStrings>
第二步、創建作業業務類
/// <summary> /// 疫情業務類 /// </summary> public class DiseaseService : IDiseaseService { private IHttpClientFactory _httpClientFactory = null; // private DiseaseDataContext _diseaseDataContext = null; /// <summary> /// /// </summary> /// <param name="httpClientFactory"></param> /// <param name="diseaseDataContext"></param> public DiseaseService(IHttpClientFactory httpClientFactory) //, DiseaseDataContext diseaseDataContext) { this._httpClientFactory = httpClientFactory; //_diseaseDataContext = diseaseDataContext; } /// <summary> /// 同步疫情 /// </summary> /// <returns></returns> public async Task<string> SyncDiseaseData() { //TODO同步疫情數據 return ""; }
第三步、在startup.cs中注入Hangfire
ConfigureServices方法中添加
services.AddHttpClient(); //注入HttpClient #region hangfire var storage = new MySqlStorage(Configuration.GetConnectionString("DiseaseJobConnection") , new MySqlStorageOptions { PrepareSchemaIfNecessary = true, TablePrefix = "Disease" }); //GlobalConfiguration.Configuration.UseStorage(new MySqlStorage(storage, new MySqlStorageOptions //{ // TransactionIsolationLevel = IsolationLevel.ReadCommitted, // 事務隔離級別。默認值為讀提交。 // QueuePollInterval = TimeSpan.FromSeconds(15), // 作業隊列輪詢間隔。默認值為15秒 // JobExpirationCheckInterval = TimeSpan.FromHours(1), // 作業過期檢查間隔(管理過期記錄)。默認為1小時 // CountersAggregateInterval = TimeSpan.FromMinutes(5), // 間隔到聚合計數器。默認為5分鍾 // PrepareSchemaIfNecessary = true, // 如果設置為true,則創建數據庫表。默認值為true // DashboardJobListLimit = 50000, // 儀表板作業列表上限。默認值為50000 // TransactionTimeout = TimeSpan.FromMinutes(1), // 事務超時。默認為1分鍾 //})); services.AddHangfire(p => p.UseStorage(storage)); #endregion services.AddScoped<DiseaseService>(); //注入業務
在Configure方法中
//hangfire app.UseHangfireServer(); app.UseHangfireDashboard(); //作業 RecurringJob.AddOrUpdate<DiseaseService>("SyncDiseaseInformation", p => p.SyncDiseaseData(), "0 9,12,18,0 * * ?");
運行程序后切換到hangfire管理頁面如下圖
MS SQL Server的表
常用命令
//支持基於隊列的任務處理:任務執行不是同步的,而是放到一個持久化隊列中,以便馬上把請求控制權返回給調用者。 var jobId = BackgroundJob.Enqueue(()=>WriteLog("隊列任務執行了!")); //延遲任務執行:不是馬上調用方法,而是設定一個未來時間點再來執行,延遲作業僅執行一次 var jobId = BackgroundJob.Schedule(()=>WriteLog("一天后的延遲任務執行了!"),TimeSpan .FromDays(1));//一天后執行該任務 //循環任務執行:一行代碼添加重復執行的任務,其內置了常見的時間循環模式,也可基於CRON表達式來設定復雜的模式。【用的比較的多】 RecurringJob.AddOrUpdate(()=>WriteLog("每分鍾執行任務!"), Cron.Minutely); //注意最小單位是分鍾 //延續性任務執行:類似於.NET中的Task,可以在第一個任務執行完之后緊接着再次執行另外的任務 BackgroundJob.ContinueWith(jobId,()=>WriteLog("連續任務!"));
配置權限
app.UseHangfireServer(); app.UseHangfireDashboard("/hangfire", new DashboardOptions { Authorization = new[] { new HangfireAuthorizationFilter() }, IgnoreAntiforgeryToken = true, AppPath = "/swagger/index.html", DashboardTitle = "Abc Sys Hangfire Dashboard" }); app.AddOrUpdateJobs();
/// <summary> /// HangfireAuthorizationFilter /// </summary> public class HangfireAuthorizationFilter : IDashboardAuthorizationFilter { /// <summary> /// no authorize /// </summary> /// <param name="context"></param> /// <returns></returns> public bool Authorize(DashboardContext context) { return true; } }