C# HangFire的使用及說明
一、含義
Hangfire 是一個(gè) .NET 后臺(tái)任務(wù)處理庫(kù),允許開發(fā)者在 ASP.NET、控制臺(tái)應(yīng)用或 Windows 服務(wù)中創(chuàng)建和管理后臺(tái)作業(yè)(如定時(shí)任務(wù)、隊(duì)列任務(wù))。
它通過持久化存儲(chǔ)(如 SQL Server、Redis)保存任務(wù)狀態(tài),確保應(yīng)用重啟后任務(wù)不丟失,并內(nèi)置 Web 儀表盤(Dashboard)實(shí)現(xiàn)任務(wù)可視化監(jiān)控
二、核心作用
1.任務(wù)調(diào)度與執(zhí)行
- 即時(shí)任務(wù)(Fire-and-forget):異步執(zhí)行,如日志記錄、郵件發(fā)送
BackgroundJob.Enqueue(() => Console.WriteLine("Task executed!")); - 延遲任務(wù)(Delayed):指定未來(lái)時(shí)間執(zhí)行,如訂單超時(shí)取消。
BackgroundJob.Schedule(() => SendReminder(), TimeSpan.FromHours(24));
- 周期性任務(wù)(Recurring):基于 Cron 表達(dá)式定時(shí)執(zhí)行,如每日數(shù)據(jù)備份。
RecurringJob.AddOrUpdate("daily-job", () => SyncData(), Cron.Daily); - 連續(xù)性任務(wù)(Continuations):任務(wù)鏈?zhǔn)綀?zhí)行,如支付成功后通知發(fā)貨
2.持久化與可靠性
任務(wù)信息存儲(chǔ)于數(shù)據(jù)庫(kù)(SQL Server/Redis 等),應(yīng)用崩潰或重啟后自動(dòng)恢復(fù)。
內(nèi)置重試機(jī)制:任務(wù)失敗時(shí)自動(dòng)重試(可配置次數(shù))
3.分布式支持
支持多節(jié)點(diǎn)部署,實(shí)現(xiàn)高可用和負(fù)載均衡。
可通過 Redis 提升性能,適應(yīng)高并發(fā)場(chǎng)景
4.可視化監(jiān)控
內(nèi)置 Dashboard 實(shí)時(shí)展示任務(wù)狀態(tài)、日志和執(zhí)行歷史,支持手動(dòng)觸發(fā)或取消任務(wù)
5.擴(kuò)展性與集成
支持依賴注入(如 Autofac、Ninject)。
可配置多隊(duì)列優(yōu)先級(jí)和并發(fā)控制
| 任務(wù)類型 | 適用場(chǎng)景 | 代碼示例 |
|---|---|---|
| 即時(shí)任務(wù) | 異步日志、郵件通知 | BackgroundJob.Enqueue(() => Log("Info")) |
| 延遲任務(wù) | 訂單超時(shí)處理、定時(shí)提醒 | BackgroundJob.Schedule(() => CancelOrder(), TimeSpan.FromMinutes(30)) |
| 周期性任務(wù) | 每日數(shù)據(jù)備份、報(bào)表生成 | RecurringJob.AddOrUpdate("backup", () => BackupData(), Cron.Daily) |
| 連續(xù)性任務(wù) | 支付→發(fā)貨→通知工作流 | BackgroundJob.ContinueJobWith(parentId, () => ShipProduct()) |
三、用法(以 ASP.NET Core 為例)
安裝與配置
Install-Package Hangfire.AspNetCore Install-Package Hangfire.Redis.StackExchange # 若用 Redis 存儲(chǔ)
服務(wù)注冊(cè)(Startup.cs)
public void ConfigureServices(IServiceCollection services) {
services.AddHangfire(config => config
.UseRedisStorage(redisConnectionString) // 或 UseSqlServerStorage()
);
services.AddHangfireServer(); // 啟動(dòng)后臺(tái)服務(wù)
}啟用 Dashboard(Startup.cs)
public void Configure(IApplicationBuilder app) {
app.UseHangfireDashboard("/jobs"); // 訪問路徑:http://domain/jobs
// 可選:添加身份驗(yàn)證過濾器
app.UseHangfireServer();
}創(chuàng)建任務(wù)示例
周期性庫(kù)存同步:
RecurringJob.AddOrUpdate("stock-sync", () => StockService.Sync(), "0 3 * * *"); // 每天3點(diǎn)執(zhí)行業(yè)務(wù)例子
我需要每天定時(shí)定點(diǎn)往大寬表中插入一次在線庫(kù)存、當(dāng)天入庫(kù)、出庫(kù)記錄
using Hangfire;
using Hangfire.Annotations;
using Hangfire.Dashboard;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using WmsService.WmsStk.StkBalances;
namespace WmsService
{
/// <summary>
/// 后臺(tái)工作任務(wù)配置
/// </summary>
public static class BackgroundConfigurer
{
/// <summary>
/// 配置服務(wù)
/// </summary>
/// <param name="services"></param>
/// <param name="configuration"></param>
public static void Configure(IServiceCollection services, IConfiguration configuration)
{
// Hangfire 任務(wù)
services.AddHangfire(config =>
{
config.UseSqlServerStorage(configuration.GetConnectionString("Wms"));
});
}
/// <summary>
/// 請(qǐng)求管道
/// </summary>
/// <param name="app"></param>
/// <param name="configuration"></param>
public static void UseBackground(IApplicationBuilder app, IConfiguration configuration)
{
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
Authorization = new[]
{
new CustomAuthorizeFilter()
}
});
app.UseHangfireServer();
//// 每天凌晨12點(diǎn)
//Cron.Daily(0, 0)
// 每天中午12點(diǎn)
//Cron.Daily(12, 0)
// 每小時(shí)執(zhí)行一次
//Cron.Hourly()
// 每30分鐘執(zhí)行一次
//Cron.MinuteInterval(30)
//定時(shí)調(diào)用方法AutoInsertInventoryRecord() 插入庫(kù)存
RecurringJob.AddOrUpdate<StkBalanceAppService>(x => x.AutoInsertInventoryRecord(), Cron.Daily(0, 1), TimeZoneInfo.Local);
}
}
public class CustomAuthorizeFilter : IDashboardAuthorizationFilter
{
public bool Authorize([NotNull] DashboardContext context)
{
return true;
}
}
}
/// <summary>
/// 定時(shí)插入庫(kù)存記錄
/// </summary>
/// <returns></returns>
public virtual async Task AutoInsertInventoryRecord()
{
//定時(shí)插入一條
var now = DateTime.Now.Date;
//now = DateTime.ParseExact("2025-02-20", "yyyy-MM-dd", CultureInfo.InvariantCulture);
var startTime = now.AddDays(-1);
//入庫(kù)總數(shù)
var inLists = await _inOrderDapperRepository.QueryInventoryReportByDay(startTime, now);
//出庫(kù)總數(shù)
var outLists = await _outInvoiceDapperRepository.QueryOutboundReportByDay(startTime, now);
//在線庫(kù)存
var onlineLists = await _outInvoiceDapperRepository.QueryOnlineBalanceReport();
var lists = new List<WmsInventoryRecord>();
foreach (var inDto in inLists)
{
WmsInventoryRecord inventoryRecord = new WmsInventoryRecord();
inventoryRecord.MaterialCode = inDto.MaterialCode;
inventoryRecord.InWareHouseQty = inDto.InQty;
lists.Add(inventoryRecord);
}
foreach (var outDto in outLists)
{
WmsInventoryRecord inventoryRecord = new WmsInventoryRecord();
inventoryRecord.MaterialCode = outDto.MaterialCode;
inventoryRecord.OutBoundQty = outDto.OutQty;
lists.Add(inventoryRecord);
}
foreach (var onlineDto in onlineLists)
{
WmsInventoryRecord inventoryRecord = new WmsInventoryRecord();
inventoryRecord.MaterialCode = onlineDto.MaterialCode;
inventoryRecord.OnlineInventory = onlineDto.OnlineQty;
lists.Add(inventoryRecord);
}
await _wmsInventoryRecordDapperRepository.InsertManyAsync(lists);
}服務(wù)注冊(cè)
//后臺(tái)工作任務(wù)配置 BackgroundConfigurer.Configure(context.Services, configuration); BackgroundConfigurer.UseBackground(app, configuration);
四、缺陷與限制
1.不支持秒級(jí)定時(shí)任務(wù)
- 最小調(diào)度單位為分鐘(依賴 NCrontab 組件),秒級(jí)任務(wù)需改用 Quartz.NET
2.內(nèi)存存儲(chǔ)(MemoryStorage)的局限性
僅適用于開發(fā)和測(cè)試環(huán)境:
應(yīng)用重啟導(dǎo)致任務(wù)丟失。
缺乏線程安全性和持久化保障
3.性能瓶頸
SQL Server 存儲(chǔ)依賴輪詢機(jī)制,高并發(fā)場(chǎng)景下可能延遲(可通過 Redis 或 MSMQ 緩解)
4.中文支持問題
部分版本(如 1.8.14)Dashboard 中文顯示異常,需降級(jí)或手動(dòng)修復(fù)
五、Hangfire與Quartz.Net對(duì)比
| 對(duì)比項(xiàng) | Hangfire | Quartz.NET |
|---|---|---|
| 最小調(diào)度粒度 | 分鐘級(jí) | 秒級(jí) |
| 可視化面板 | 內(nèi)置 Dashboard | 需第三方擴(kuò)展 |
| 分布式支持 | 基礎(chǔ)多節(jié)點(diǎn) | 原生集群支持 |
| 適用場(chǎng)景 | 常規(guī)后臺(tái)任務(wù)、需可視化監(jiān)控 | 復(fù)雜調(diào)度、金融級(jí)精準(zhǔn)定時(shí) |
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
C#中同步和異步回調(diào)的實(shí)現(xiàn)
在C#中,同步回調(diào)和異步回調(diào)都是用于處理任務(wù)或事件完成的機(jī)制,本文主要介紹了C#中同步和異步回調(diào)的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2025-04-04
結(jié)合.net框架在C#派生類中觸發(fā)基類事件及實(shí)現(xiàn)接口事件
這篇文章主要介紹了結(jié)合.net框架在C#派生類中觸發(fā)基類事件及實(shí)現(xiàn)接口事件,示例的事件編程中包括接口和類的繼承等面向?qū)ο蟮幕A(chǔ)知識(shí),需要的朋友可以參考下2016-02-02
C#實(shí)現(xiàn)字符、ASCII碼和數(shù)字之間進(jìn)行轉(zhuǎn)換的方法大全
ASCII(美國(guó)信息交換標(biāo)準(zhǔn)代碼)是計(jì)算機(jī)科學(xué)中最常用的字符編碼標(biāo)準(zhǔn)之一,在C#開發(fā)中,經(jīng)常需要在字符、ASCII碼和數(shù)字之間進(jìn)行轉(zhuǎn)換,本文將詳細(xì)介紹C#中實(shí)現(xiàn)這些轉(zhuǎn)換的各種方法,需要的朋友可以參考下2025-10-10

