.NET Core 8 中使用 Hangfire 进行后台作业管理
在现代应用程序中,将耗时的任务交由后台处理是提高系统性能的常用技术。如果没有后台任务的支持,耗时操作可能会显著影响系统性能,进而导致糟糕的用户体验,因为系统响应时间会变长。
本文将详细讲解如何在 ASP.NET Core 中执行后台任务,采用的方案并非万能之法,后台任务也存在一些挑战和限制。本文将带你逐步了解如何使用非常流行的开源库 Hangfire 来创建、调度并执行后台任务。
一、背景介绍
首先,我们将通过 Visual Studio 创建一个简单的控制台应用,并安装 Hangfire 所需的依赖包。虽然我们以控制台应用为例,但你也可以在 .NET API 项目 中触发后台任务。
二、准备工作
创建一个 .NET API 项目
-
创建一个名为 VideoProcessor
的 .NET API 项目(可以根据实际需求自由命名)。 -
在项目中安装以下必要的包:
dotnet add package Hangfire.Core
dotnet add package Hangfire.AspNetCore
dotnet add package Hangfire.PostgreSql
Hangfire 的主要组成部分:
-
存储:Hangfire 将存储有关正在运行、计划或排队的任务的必要信息。 -
客户端:负责创建任务并将其保存到存储中。 -
服务器:服务器从存储中查询任务并执行。Hangfire 提供了在任意进程中运行服务器的能力,即使进程终止,任务也会在重启后自动重试。 -
仪表板:提供一个直观的用户界面来监控和调试任务,非常方便。
三、Hangfire 配置
配置数据库连接
在 appsettings.json
文件中添加数据库连接字符串,Hangfire 将使用该数据库存储后台任务的相关信息:
"ConnectionStrings": {
"HangfireConnection": "YourDbServer"
}
注册 Hangfire 服务
在 Startup.cs
中,向依赖注入容器注册 Hangfire 服务,指定使用 PostgreSQL 作为存储:
services.AddHangfire(config =>
config.UsePostgreSqlStorage(configuration.GetConnectionString("HangfireConnection"))
);
说明:这段代码通过 UsePostgreSqlStorage
方法将 Hangfire 的存储配置为使用 PostgreSQL 数据库。
启用 Hangfire 仪表板和服务器
app.UseHangfireServer();
app.UseHangfireDashboard();
说明:这两行代码启用了 Hangfire 的服务器和仪表板。仪表板提供了监控任务的功能,默认情况下,仪表板对所有人开放。
限制仪表板的访问权限
为了保护 /hangfire
仪表板,可以通过授权限制只有认证用户才能访问:
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
Authorization = new[] { new MyAuthorizationFilter() }
});
说明:Authorization
选项指定了自定义的授权策略,确保只有通过认证的用户才能访问 Hangfire 仪表板。
四、创建任务
Hangfire 支持多种任务类型,包括立即执行的任务(Fire-and-Forget)、延迟任务、定时任务以及依赖任务。下面将逐一介绍这些任务类型。
1. Fire-and-Forget 任务
Fire-and-Forget 任务是一种最常见的后台任务类型,任务一旦被加入队列,便会立即在后台执行:
BackgroundJob.Enqueue(() =>
Console.WriteLine("Fire-and-Forget 任务已执行。"));
说明:BackgroundJob.Enqueue
方法将任务加入队列后,Hangfire 会自动安排该任务立即执行。
2. 延迟任务
延迟任务允许我们将任务的执行延迟一段时间,例如在 10 秒后执行某个任务:
BackgroundJob.Schedule(
() => Console.WriteLine("延迟任务将在 10 秒后执行。"),
TimeSpan.FromSeconds(10)
);
说明:BackgroundJob.Schedule
方法接收两个参数,第一个是要执行的任务,第二个是延迟时间。
五、高级任务调度
1. 定时任务(Recurring Jobs)
定时任务会根据设定的 CRON 表达式重复执行,例如每分钟执行一次任务:
RecurringJob.AddOrUpdate(
"my-recurring-job",
() => Console.WriteLine("每分钟执行一次的定时任务。"),
Cron.Minutely()
);
说明:Cron.Minutely()
是一个内置的 CRON 表达式,表示每分钟执行一次任务。
2. 依赖任务(Continuation Jobs)
依赖任务会在父任务完成后执行,这在任务之间存在依赖关系时非常有用,例如:处理完数据后再发送通知。
var parentJobId = BackgroundJob.Enqueue(() =>
Console.WriteLine("父任务已执行。"));
BackgroundJob.ContinueWith(parentJobId, () =>
Console.WriteLine("依赖任务在父任务之后执行。"));
说明:ContinueWith
方法可以让任务按照依赖关系串联执行。
六、多线程环境中的任务管理
在多线程环境中,管理多个任务变得更加复杂。Hangfire 提供了多线程任务的并发处理功能,通过设置 Worker 线程数量来控制并发度。
var options = new BackgroundJobServerOptions
{
WorkerCount = Environment.ProcessorCount * 5
};
app.UseHangfireServer(options);
说明:WorkerCount
指定了并发执行的线程数量,该数值根据系统 CPU 核心数动态计算。
七、任务优先级管理
可以为不同的任务设置不同的优先级,Hangfire 将根据优先级队列依次处理任务:
var options = new BackgroundJobServerOptions
{
Queues = new[] { "critical", "default", "low" }
};
app.UseHangfireServer(options);
说明:通过 Queues
属性,我们可以定义不同的优先级队列。任务将按以下顺序执行:
-
先执行 "critical" 队列中的任务。 -
若 "critical" 队列为空,再执行 "default" 队列中的任务。 -
最后执行 "low" 队列中的任务。
// 高优先级队列任务
BackgroundJob.Enqueue(() => Console.WriteLine("执行高优先级任务"), "critical");
// 默认队列任务
BackgroundJob.Enqueue(() => Console.WriteLine("执行默认优先级任务"));
// 低优先级队列任务
BackgroundJob.Enqueue(() => Console.WriteLine("执行低优先级任务"), "low");
八、任务监控与最佳实践
Hangfire 的仪表板提供了方便的任务监控功能,帮助开发者和系统管理员追踪任务状态、检查进度并处理任务执行中的错误。
常见任务状态
-
Enqueued:任务已加入队列,等待执行。 -
Processing:任务正在执行中。 -
Succeeded:任务成功完成。 -
Failed:任务执行失败。 -
Deleted:任务已被删除。
最佳实践
-
使用特定的队列来为任务分配不同的优先级。 -
配置任务自动重试机制,使用 [AutomaticRetry(Attempts = 0)]
属性指定重试次数。 -
实现任务超时机制,防止任务长时间挂起。 -
记录任务执行中的错误,并在仪表板上调试。 -
测试任务在生产环境前的表现,确保系统资源不会被大量耗尽。
九、总结
Hangfire 是一个功能强大的库,能够轻松管理和调度后台任务。在本文中,我们探讨了 Hangfire 在 ASP.NET Core 中的应用,从基本任务类型到高级的任务调度和监控。通过结合 Hangfire 的仪表板和多线程环境,我们可以更高效地处理耗时任务,并提高应用程序的性能和用户体验。