安裝
NuGet 上有幾個可用的Hangfire 的軟件包。如果在ASP.NET應用程序中安裝HangFire,並使用Sql Server作為存儲器,那么請在Package Manager Console窗口中鍵入以下命令:
PM> Install-Package Hangfire
配置
在安裝package后,添加或者更新以下幾行到Owin Startp類:
using Hangfire; // ... public void Configuration(IAppBuilder app) { GlobalConfiguration.Configuration.UseSqlServerStorage("<connection string or its name>"); app.UseHangfireDashboard(); app.UseHangfireServer(); }
需要配置授權
默認情況下,只有本地有權限訪問Hangfire儀表板。如果需要授權遠程訪問,那么儀表板的授權必須進行相應的配置。
然后打開Hangfire儀表板來測試您的配置。編譯項目並在瀏覽器中打開以下URL:
1
|
http:
//<your-site>/hangfire
|
用法
添加工作
HangFire處理不同類型的后台任務,並且使用一個獨立的上下文環境調用他們。
Fire-And-forget(發布/訂閱)
這是一個主要的后台任務類型,持久化消息隊列會去處理這個任務。當你創建了一個發布/訂閱任務,該任務會被保存到默認隊列里面(默認隊列是"Default",但是支持使用多隊列)。多個專注的工作者(Worker)會監聽這個隊列,並且從中獲取任務並且完成任務。
BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget"));
延遲
如果想要延遲某些任務的執行,可以是用以下任務。在給定延遲時間后,任務會被排入隊列,並且和發布/訂閱任務一樣執行。
BackgroundJob.Schedule(() => Console.WriteLine("Delayed"), TimeSpan.FromDays(1));
循環
按照周期性(小時,天等)來調用方法,請使用RecurringJob
類。在復雜的場景,您可以使用CRON表達式指定計划時間來處理任務。
RecurringJob.AddOrUpdate(() => Console.WriteLine("Daily Job"), Cron.Daily);
連續
連續性允許您通過將多個后台任務鏈接在一起來定義復雜的工作流。
var id = BackgroundJob.Enqueue(() => Console.WriteLine("Hello, ")); BackgroundJob.ContinueWith(id, () => Console.WriteLine("world!"));
釋放
Hangfire將您的任務保存到持久化庫匯總,並且以可靠的方式處理它們。這意味着,你可以中斷Hangfire Worder的線程,重新加載應用程序域,或者終止程序,即使這樣您的任務仍會被處理。只有在你代碼的最后一行執行完成,Hangfire才會標記這個任務完成。並且知道任務可能在最后一行代碼執行之前失敗。它包含多種 自動-重試機制,它可以自動處理在存儲或代碼執行過程中發生的錯誤。
這對於通用托管環境(如IIS Server)非常重要。它們可以包含不同的優化,超時和錯誤處理代碼(可能導致進程終止)來防止不好的事情發生。如果您沒有使用可靠的處理和自動機制,您的工作可能會丟失。您的最終用戶可能無限期等待某些任務,如電子郵件,報告,通知等。
但是當您的存儲空間破損時,Hangfire無法做任何事情。請為您的存儲使用不同的故障切換策略,以保證在發生災難時處理每個作業。
原文地址:http://docs.hangfire.io/en/latest/quick-start.html
HangFire簡述:
分布式后端作業調度框架服務,我們只需要關心業務邏輯代碼,而不用關心調度機制,支持.net framework和.net core
HangFire基本結構:
客戶端(創建任務)、服務端(執行任務)、數據庫(存儲任務列表和執行狀況)、儀表盤(在網站上對任務進行監控查看和各種操作)
HangFire適用場景:
定時執行任務、循環執行任務、異步執行耗時任務、A任務執行完成再執行B任務、批量執行任務
HangFire官網: https://www.hangfire.io/
HangFire中文文檔:http://koukouge-hangfire.daoapp.io/quick-start.html
HangFire英文文檔:http://docs.hangfire.io/en/latest/quick-start.html
HangFire源碼地址: https://github.com/HangfireIO
實戰經驗分享:
網上資料不是很多 都是按照官方例子在講解,缺少很多關鍵性的概念講解,導致很多伙計在實戰中遇到各種坑。
1、客戶端:創建任務-->1、配置HangFire數據庫連接 2、創建任務(在創建任務的時候HangFire會自動將任務序列化並存儲到數據)
2、服務端:執行任務-->1、配置HangFire數據庫連接 2、從HangFire數據庫系統表讀取客戶端創建的任務然后開線程並行執行,任務之間不沖突。(服務端可宿主在Windows服務、控制台程序、IIS中…)
3、數據庫:HangFire程序框架表-->創建任務的時候HangFire會自動生成無需關心,但要注意如果采用現有的數據庫,必須保證數據庫中沒有重名的表,否則你懂(aggregatedcounter、counter、distributedlock、hash、job、jobparameter、jobqueue、jobstate、list、server、set、state),數據庫可采用 MySQL ,MSSQL,Redis視需要而定
4、儀表盤:展示作業列表執行狀態和結果等相關信息-->在.Net WebForm或.Net MVC 或.NetCore MVC網站程序對接HangFire數據庫,MVC 對接方式和WebForm略微不同 請參考官方文檔
如何正確理解架設部署上述4個板塊:
重點說客戶端、服務端、儀表盤直之間的關系,數據庫就不用多說了
方案1(不推薦):客戶端A、服務端B、儀表盤C 分別運行在3個獨立的項目中
優缺點:沒什么優點,而且AB分開會導致服務端B從數據庫提取任務列表,准備反向加載程序集執行任務的時候,在自己的程序代碼中找不到對應的業務邏輯代碼或者引用類,因為業務邏輯代碼是在客戶端A項目中創建,自然業務邏輯類及功能代碼都在A項目的程序集中,自然找不到。
例子:客戶端A創建的作業是引用YourOwnJobLibrary.dll類中 ShowMeTheMoney() 方法,而服務端B中沒有引用YourOwnJobLibrary.dll 所以無法執行任務ShowMeTheMoney(),
報錯:System.IO.FileNotFoundException
Could not load file or assembly 'DotNetFrameWorkConsoleApplicationHangFire, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. ???????????
System.IO.FileNotFoundException: Could not load file or assembly 'DotNetFrameWorkConsoleApplicationHangFire, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. ???????????
File name: 'DotNetFrameWorkConsoleApplicationHangFire, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMarkHandle stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName, ObjectHandleOnStack type, ObjectHandleOnStack keepalive)
at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName)
at System.RuntimeType.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark)
at System.Type.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase)
at Hangfire.Storage.InvocationData.Deserialize()
解決方案:讓服務端B也引用YourOwnJobLibrary.dll即可,但是這並不是我們想要的結果,以后更新服務什么的還得兩頭更新很麻煩。
方案2(推薦):客戶端A、服務端B在同一個項目中,儀表盤C獨立網站項目中
優缺點:這樣比較合理,更新服務方便,即便沒有儀表盤C,作業正常調度執行;適合后台相對固定的作業。
可以將AB放在Windows服務項目中(VS中可以創建),這樣系統重啟什么的毫無顧慮,更新服務程序的時候只需停止服務->替換程序->開啟服務即可。
方案3(還行):客戶端A、服務端B、儀表盤C在同一網站項目只能是網站項目,因為儀表盤只能在Web項目(API、WebForm、MVC )中
優缺點:視情況也未嘗不可,如果宿主在IIS中,IIS默認20分鍾沒有人訪問會停止,HangFire作業服務也會定制,可將此時間在IIS配置中延長,比較適合任務經常需要靈活變動處理的場景。
重要信息備注:
注1:創建任務可以是在控制台程序Main方法中執行一次把任務Load到數據庫,或則在網站上用戶點擊某個按鈕執行后端方法創建。
注2:服務端比較靈活,可宿主在Windows服務、控制台程序、IIS中…
注3:首次啟動連接數據庫時,會自動生成12張系統表,請確保現有庫中不存在以下表名:aggregatedcounter、counter、distributedlock、hash、job、jobparameter、jobqueue、jobstate、list、server、set、state
注4:原則上同一台電腦上只需要1個服務端存在,測試中發現這么一種情況:服務端B宿主在D控制台程序中,因誤操作在儀表盤C網站項目中也啟動一個HangeFire宿主服務E,最后的結果是服務端B的程序失效,服務端E正常運作,但是儀表盤上顯示找不到任務作業對應的程序集,因為程序集在服務端B程序中,如方案1的System.IO.FileNotFoundException…
注5:HangFire執行的任務里面如果涉及到C盤創建文件夾 可能會因為權限問題 創建失敗,采用管理員權限運行程序即可創建
實例:按照方案2思路測試
- 創建一個.net core 2.0控制台項目(.net framework/.net core2.0都行)
- 安裝nuget Hangfire(針對控制台程序可以只安裝Hangfire.core即可 )
- 安裝nuget HangFire.MySql.Core(.net framework 也引用此包 如果用HangFire.MySql 下面的配置數據庫鏈接事變)
- 安裝好后就可以在Main方法中使用了
注:控制台程序關閉,也就是HangFire宿主程序停止,作業無法繼續執行,想檢測服務作業是否在執行,可定時往記事本中寫入當前時間。
5、網站(.net core)中配置HangFire儀表盤:( .net framework 的網站配置不一樣 尚未測試)
注1:app.UseHangfireDashboard(); 是讓網站僅僅可以訪問HangFire數據庫的作業詳情,不負責業務代碼的執行。
注2:app.UseHangfireServer();是讓HangFire服務宿主在Web程序中,參加上面方案2和方案3,如果是方案2則不應該添加此語句,方案3則添加此語句。
運行項目訪問HangFire儀表盤: http://localhost:56013/hangfire/