Hangfire详解
Hangfire詳解
零、文章目錄
一、概述
1、概述
在 .NET 和 .NET Core 應(yīng)用程序中執(zhí)行后臺(tái)處理的簡(jiǎn)單方法。無需 Windows 服務(wù)或單獨(dú)的進(jìn)程。由持久存儲(chǔ)支持。開源且免費(fèi)用于商業(yè)用途。
官網(wǎng)地址:https://www.hangfire.io/
文檔地址:https://docs.hangfire.io/en/latest/
2、架構(gòu)組成
Hangfire由三個(gè)主要部分組成:客戶端、存儲(chǔ)和服務(wù)器。
(1)要求
Hangfire 適用于大多數(shù) .NET 平臺(tái):.NET Framework 4.5 或更高版本、.NET Core 1.0 或更高版本,或任何與 .NET Standard 1.3 兼容的平臺(tái)。
您可以將它與幾乎任何應(yīng)用程序框架集成,包括 ASP.NET、ASP.NET Core、控制臺(tái)應(yīng)用程序、Windows 服務(wù)、WCF等。
(2)存儲(chǔ)
存儲(chǔ)是 Hangfire 保存與后臺(tái)作業(yè)處理相關(guān)的所有信息的地方。類型、方法名稱、參數(shù)等所有細(xì)節(jié)都被序列化并放入存儲(chǔ)中,沒有數(shù)據(jù)保存在進(jìn)程的內(nèi)存中。存儲(chǔ)子系統(tǒng)在 Hangfire 中被很好地抽象出來,可以為 RDBMS 和 NoSQL 解決方案實(shí)現(xiàn)。
這是開始使用框架之前所需的唯一配置。以下示例顯示如何使用 SQL Server 數(shù)據(jù)庫(kù)配置 Hangfire。請(qǐng)注意,連接字符串可能會(huì)有所不同,具體取決于您的環(huán)境。
GlobalConfiguration.Configuration .UseSqlServerStorage(@"Server=.\SQLEXPRESS; Database=Hangfire.Sample; Integrated Security=True");(3)客戶端
客戶端可以創(chuàng)建任何類型的后臺(tái)作業(yè):即時(shí)任務(wù)(立即執(zhí)行),延遲任務(wù)(在一段時(shí)間后執(zhí)行調(diào)用),定時(shí)任務(wù)(每小時(shí)、每天執(zhí)行方法等)。
Hangfire 不需要你創(chuàng)建特殊的類。后臺(tái)作業(yè)基于常規(guī)的靜態(tài)或?qū)嵗椒ㄕ{(diào)用。
//實(shí)例方法調(diào)用 var client = new BackgroundJobClient(); client.Enqueue(() => Console.WriteLine("Hello world!"));//靜態(tài)方法調(diào)用 BackgroundJob.Enqueue(() => Console.WriteLine("Hello world!"));(4)服務(wù)器
后臺(tái)作業(yè)由Hangfire Server處理。它被實(shí)現(xiàn)為一組專用的(不是線程池的)后臺(tái)線程,它們從存儲(chǔ)中獲取作業(yè)并處理它們。服務(wù)器還負(fù)責(zé)保持存儲(chǔ)清潔并自動(dòng)刪除舊數(shù)據(jù)。
Hangfire 為每個(gè)存儲(chǔ)后端使用可靠的獲取算法,因此您可以在 Web 應(yīng)用程序內(nèi)部開始處理,而不會(huì)在應(yīng)用程序重新啟動(dòng)、進(jìn)程終止等時(shí)丟失后臺(tái)作業(yè)的風(fēng)險(xiǎn)。
您只需要?jiǎng)?chuàng)建一個(gè)BackgroundJobServer類的實(shí)例并開始處理:
using (new BackgroundJobServer()) {Console.WriteLine("Hangfire Server started. Press ENTER to exit...");Console.ReadLine(); }3、特性
4、分布式
客戶端創(chuàng)建任務(wù)到存儲(chǔ)和服務(wù)器從存儲(chǔ)拉取任務(wù)執(zhí)行之間是可以分開執(zhí)行的。
通過同一個(gè)存儲(chǔ)進(jìn)行交換數(shù)據(jù),而不直接交換數(shù)據(jù),可以實(shí)現(xiàn)客戶端和服務(wù)器的解耦。
二、快速開始
1、nuget引入程序集
Hangfire 作為幾個(gè) NuGet 包分發(fā),從主要包 Hangfire.Core 開始,它包含所有主要類和抽象。Hangfire.SqlServer 等其他包提供功能或抽象實(shí)現(xiàn)。要開始使用 Hangfire,請(qǐng)安裝主軟件包并選擇一個(gè)可用的存儲(chǔ)。
這里我是用MySql作為Hangfire的Storage。Hangfire 官方在免費(fèi)版中只提供了 SqlServer 接入的支持,在收費(fèi)版多一個(gè) Redis。需要 MongoDB、SqlServer 、PostgreSql、SQLite 等其他 Storages 的可以自己尋找第三方的開源項(xiàng)目,這里有一個(gè)官方推薦的擴(kuò)展清單https://www.hangfire.io/extensions.html,清單中列出了一些其他種類的 Storages。
Hangfire.Core 版本1.7.30,Net5 Hangfire.MySqlStorage mysql數(shù)據(jù)庫(kù)存儲(chǔ)2、安裝數(shù)據(jù)庫(kù)
安裝數(shù)據(jù)庫(kù)
安裝數(shù)據(jù)庫(kù)可以使用docker容器化安裝,簡(jiǎn)單易用,一行命令解決,docker相關(guān)知識(shí)可以參考docker詳解。
docker run --name mysqlserver -v /data/mysql/conf:/etc/mysql/conf.d -v /data/mysql/logs:/logs -v /data/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d -i -p 3306:3306 mysql:latest --lower_case_table_names=1| –name mysqlserver | 容器運(yùn)行的名字 |
| -v /data/mysql/conf:/etc/mysql/conf.d | 將宿主機(jī)/data/mysql/conf映射到容器/etc/mysql/conf.d |
| -v /data/mysql/logs:/logs | 將宿主機(jī)/data/mysql/logs映射到容器/logs |
| -v /data/mysql/data:/var/lib/mysql | 將宿主機(jī)/data/mysql/data映射到容器 /var/lib/mysql |
| -e MYSQL_ROOT_PASSWORD=123456 | 數(shù)據(jù)庫(kù)初始密碼123456 |
| -p 3306:3306 | 將宿主機(jī)3306端口映射到容器的3306端口 |
| –lower_case_table_names=1 | 設(shè)置表名忽略大小寫,只能首次修改,后續(xù)無法修改 |
創(chuàng)建數(shù)據(jù)庫(kù)hangfiredb
3、代碼實(shí)現(xiàn)
使用GlobalConfiguration類執(zhí)行配置。它的Configuration屬性提供了很多擴(kuò)展方法,既來自 Hangfire.Core,也來自其他包。
方法調(diào)用可以鏈?zhǔn)秸{(diào)用,因此無需一次又一次地使用類名。全局配置是為了簡(jiǎn)單起見,幾乎每個(gè) Hangfire 類都允許您為存儲(chǔ)、過濾器等指定覆蓋。在 ASP.NET Core 環(huán)境中,全局配置類隱藏在AddHangfire方法中。
internal class Program {static void Main(string[] args){//配置存儲(chǔ)GlobalConfiguration.Configuration.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)//全局配置兼容版本,向下兼容.UseColouredConsoleLogProvider()//輸出日志.UseSimpleAssemblyNameTypeSerializer()//使用簡(jiǎn)單程序集名稱類型序列化程序.UseRecommendedSerializerSettings()//使用推薦的序列化配置.UseStorage(new MySqlStorage("server=服務(wù)器IP地址;Database=hangfiredb;user id=root;password=123456;SslMode=none",new MySqlStorageOptions{TransactionIsolationLevel = IsolationLevel.ReadCommitted,QueuePollInterval = TimeSpan.FromSeconds(15),JobExpirationCheckInterval = TimeSpan.FromHours(1),CountersAggregateInterval = TimeSpan.FromMinutes(5),PrepareSchemaIfNecessary = true,DashboardJobListLimit = 50000,TransactionTimeout = TimeSpan.FromMinutes(1),TablesPrefix = "Hangfire"}));//客戶端創(chuàng)建任務(wù)BackgroundJob.Enqueue(() => Console.WriteLine("Hello, world!"));//服務(wù)器運(yùn)行任務(wù)using (var server = new BackgroundJobServer()){Console.ReadLine();}} }可選參數(shù)說明:
- TransactionIsolationLevel- 事務(wù)隔離級(jí)別。默認(rèn)為已提交讀。
- QueuePollInterval- 作業(yè)隊(duì)列輪詢間隔。默認(rèn)值為 15 秒。
- JobExpirationCheckInterval- 作業(yè)過期檢查間隔(管理過期記錄)。默認(rèn)值為 1 小時(shí)。
- CountersAggregateInterval- 聚合計(jì)數(shù)器的間隔。默認(rèn)為 5 分鐘。
- PrepareSchemaIfNecessary- 如果設(shè)置為true,它會(huì)創(chuàng)建數(shù)據(jù)庫(kù)表。默認(rèn)為true。
- DashboardJobListLimit- 儀表板作業(yè)列表限制。默認(rèn)值為 50000。
- TransactionTimeout- 交易超時(shí)。默認(rèn)值為 1 分鐘。
- TablesPrefix- 數(shù)據(jù)庫(kù)中表的前綴。默認(rèn)為無
4、運(yùn)行結(jié)果
(1)第一次運(yùn)行數(shù)據(jù)庫(kù)表會(huì)自動(dòng)創(chuàng)建
(2)任務(wù)執(zhí)行成功
三、支持多種任務(wù)類型
1、即時(shí)任務(wù)
即時(shí)任務(wù)作業(yè)只執(zhí)行一次,幾乎在創(chuàng)建后 立即執(zhí)行。
var jobId = BackgroundJob .Enqueue(() => Console .WriteLine( "即時(shí)任務(wù)!" ));2、延遲任務(wù)
延遲的作業(yè)也只執(zhí)行一次,但不是在一定時(shí)間間隔后立即執(zhí)行。
var jobId2 = BackgroundJob.Schedule(() => Console.WriteLine("延遲任務(wù)!"), TimeSpan.FromMilliseconds(10));3、重復(fù)任務(wù)
重復(fù)作業(yè)在指定的CRON 計(jì)劃上****多次觸發(fā)。
RecurringJob.AddOrUpdate("myrecurringjob", () => Console.WriteLine("重復(fù)任務(wù)!"), Cron.Minutely);4、繼續(xù)任務(wù)
當(dāng)其父作業(yè)完成時(shí)繼續(xù)執(zhí)行。
BackgroundJob.ContinueJobWith(jobId2,() => Console.WriteLine("jobId2執(zhí)行完了再繼續(xù)執(zhí)行!"));5、批次任務(wù)-收費(fèi)
批處理是一組以原子方式創(chuàng)建并被視為單個(gè)實(shí)體的后臺(tái)作業(yè)。
var batchId = BatchJob.StartNew(x => {x.Enqueue(() => Console.WriteLine("Job 1"));x.Enqueue(() => Console.WriteLine("Job 2")); });6、批處理繼續(xù)任務(wù)–收費(fèi)
當(dāng)父批處理中的所有后臺(tái)作業(yè)****完成時(shí), 將觸發(fā)批處理繼續(xù)。
BatchJob.ContinueBatchWith(batchId, x => {x.Enqueue(() => Console.WriteLine("Last Job")); });7、封裝任務(wù)
業(yè)務(wù)邏輯復(fù)雜的時(shí)候可以封裝到方法中
//封裝的方法 public class SyncUserDataSchedule {public void SyncUserData(){Console.WriteLine($"同步用戶數(shù)據(jù)--{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");} } RecurringJob.AddOrUpdate<SyncUserDataSchedule>(c => c.SyncUserData(), Cron.Minutely);四、集成到Asp.NetCore5框架
1、需求
儀表盤
權(quán)限控制
http請(qǐng)求任務(wù)
請(qǐng)求參數(shù)
自定義任務(wù)
corn配置
2、nuget引入程序集
Microsoft.AspNetCore.App Hangfire.Core Hangfire.MySqlStorage --mysql數(shù)據(jù)庫(kù)存儲(chǔ) Hangfire.AspNetCore --AspNetCore支持 Hangfire.Dashboard.BasicAuthorization --可視化+權(quán)限控制 Hangfire.HttpJob --httpJob3、創(chuàng)建數(shù)據(jù)庫(kù)
同上快速開始,創(chuàng)建hangfiredb
4、配置文件配置
添加連接字符串和打印日志等級(jí)
Allow User Variables=true;這個(gè)參數(shù)重要,否則頁(yè)面無法正常顯示。
{"ConnectionStrings": {"HangfireConnection":"server=服務(wù)器IP地址;Database=hangfiredb;userid=root;password=123456;SslMode=none;Allow User Variables=true;"},"Logging": {"LogLevel": {"Default": "Information","Microsoft": "Warning","Microsoft.Hosting.Lifetime": "Information","Hangfire": "Information"}},"AllowedHosts": "*" }5、Startup支持hangfire
賬號(hào)驗(yàn)證也可以配置到數(shù)據(jù)庫(kù)和配置文件等
public class Startup {public Startup(IConfiguration configuration){Config = configuration;}public IConfiguration Config { get; }// This method gets called by the runtime. Use this method to add services to the container.// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940public void ConfigureServices(IServiceCollection services){// Add Hangfire services.services.AddHangfire(configuration => configuration.SetDataCompatibilityLevel(CompatibilityLevel.Version_170).UseSimpleAssemblyNameTypeSerializer().UseRecommendedSerializerSettings() .UseStorage(new MySqlStorage(Config["ConnectionStrings:HangfireConnection"],new MySqlStorageOptions{TransactionIsolationLevel = IsolationLevel.ReadCommitted,QueuePollInterval = TimeSpan.FromSeconds(15),JobExpirationCheckInterval = TimeSpan.FromHours(1),CountersAggregateInterval = TimeSpan.FromMinutes(5),PrepareSchemaIfNecessary = true,DashboardJobListLimit = 50000,TransactionTimeout = TimeSpan.FromMinutes(1),TablesPrefix = "Hangfire"})).UseHangfireHttpJob());}// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.public void Configure(IApplicationBuilder app, IWebHostEnvironment env){if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.UseHangfireServer();app.UseHangfireDashboard("/hangfire", new DashboardOptions{Authorization = new[] { new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions{RequireSsl = false,SslRedirect = false,LoginCaseSensitive = true,Users = new []{new BasicAuthAuthorizationUser{Login = "admin",PasswordClear = "test"}}})}});app.UseRouting();app.UseEndpoints(endpoints =>{endpoints.MapGet("/", async context =>{await context.Response.WriteAsync("Hello World!");});});} }6、運(yùn)行成果
訪問頁(yè)面http://localhost:8848/hangfire,首次需要驗(yàn)證賬號(hào)
登陸之后可以看到整個(gè)儀表盤和配置界面
Job管理:儀表盤主頁(yè)
作業(yè):作業(yè)的一些執(zhí)行情況
重試:一些失敗重試的作業(yè)信息
周期性作業(yè):可以配置一些周期性作業(yè)
服務(wù)器:展示當(dāng)前運(yùn)行任務(wù)的服務(wù)器信息
五、集成到Asp.NetCore6框架
其他部分同Asp.NetCore5,Program如下
public class Program {public static void Main(string[] args){var builder = WebApplication.CreateBuilder(args);// Add Hangfire services.builder.Services.AddHangfire(configuration => configuration.SetDataCompatibilityLevel(CompatibilityLevel.Version_170).UseSimpleAssemblyNameTypeSerializer().UseRecommendedSerializerSettings().UseStorage(new MySqlStorage(builder.Configuration["ConnectionStrings:HangfireConnection"],new MySqlStorageOptions{TransactionIsolationLevel = IsolationLevel.ReadCommitted,QueuePollInterval = TimeSpan.FromSeconds(15),JobExpirationCheckInterval = TimeSpan.FromHours(1),CountersAggregateInterval = TimeSpan.FromMinutes(5),PrepareSchemaIfNecessary = true,DashboardJobListLimit = 50000,TransactionTimeout = TimeSpan.FromMinutes(1),TablesPrefix = "Hangfire"})).UseHangfireHttpJob());var app = builder.Build();app.UseHangfireServer();app.UseHangfireDashboard("/hangfire", new DashboardOptions{Authorization = new[] { new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions{RequireSsl = false,SslRedirect = false,LoginCaseSensitive = true,Users = new []{new BasicAuthAuthorizationUser{Login = "admin",PasswordClear = "test"}}})}});app.MapGet("/", () => "Hello World!");app.Run();} }六、最佳實(shí)踐建議
1、業(yè)務(wù)和定時(shí)任務(wù)解耦
定時(shí)任務(wù)只配置請(qǐng)求業(yè)務(wù)api,將業(yè)務(wù)封裝到api對(duì)外暴露api,實(shí)現(xiàn)業(yè)務(wù)和定時(shí)任務(wù)的解耦。
總結(jié)
以上是生活随笔為你收集整理的Hangfire详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Fluent验证案例05:管道中的泊肃叶
- 下一篇: c++封装webrtc sdk(二):在