使用.NET 6 搭建 Hangfire 任务调度应用
分享目标:
- 了解.Net 6 web 应用模板
- Hangfire 的搭建与使用
Part 1 .NET Core
前言
微软在 2022 年 8 月 9 日 发布了.NET 7 Preview 7,预计将于 11 月份正式发布.NET 7。前几天,他们还正式发布了.NET 多平台应用 UI (.NET MAUI) 。.NET 7 最终将统一所有不同的 .NET 开发工具组件,使开发人员能够在同一套类库、运行时和编译器上构建所有类型的应用(桌面、移动、Web 等)。
创建 Asp.Net Core Web 应用
dotnet new sln -n HangfireDemo
dotnet new web -n Hangfire.Server
dotnet new console -n Hangfire.Client
dotnet sln add Hangfire.Client Hangfire.Server
项目结构
Program.cs 概述
- 代码简洁的原因:
顶级语句
=> (C# 9 )省略了 Main 方法的主入口
全局Using
=> (C# 10)省略了 Using 命令
Minimal API
=> Minimal API 是.Net 6 中新增的模板,借助 C# 10 的一些特性以最少的代码运行一个 Web 服务。
- 这个文件中做了什么:
var builder = WebApplication.CreateBuilder(args);
//初始化一个有默认配置的WebApplicationBuilder实例
//WebApplicationBuilder用来构建web应用程序和服务
builder.Services.AddControllers(); //将服务注册到容器中
var app = builder.Build(); // 创建 WebApplication.
app.MapGet("/", () => "Hello World!"); // 匹配指定模式的HTTP GET请求。
app.UseRouting(); //配置请求管道的中间件
app.Run(); //运行应用程序
用一张图片说明
- 添加了一个
Host
类型的字段_Host
, 该字段用于直接使用host
实例。 - 创建了一个
EndpointDataSource
的列表,用于配置endpoint
- 创建一个
ApplicationBuilder
的实例,这个实例主要用于构建 middleware pipeline.
IWebHostEnvironment
: 取得环境变量,ContentRoot
以及其他的各种类似的变量。IServiceCollection
: 用于注册DI
服务,它的作用和老版的ConfigureService
是一致的。ConfigurationManager
: 配置信息,关于这个类,可以看之前的文章了解更多。ILoggingBuilder
: 用户注册日志提供者,和Generic Host
上的ConfigureLogging()
是一样的功能。WebHost
和Host
分别代表了类ConfigureWebHostBuilder
和ConfigureHostBuilder
,之前的很多扩展方法现在可以直接在这两个属性上使用
对 Asp.Net Core 的项目结构有了一定了解后,我们接下来就开始使用这个项目模板搭建 Hangfire 应用。
Part 2 Hangfire
一句话概括,Hangfire 是开源的.NET 非同步任务调度框架,并且还有丰富的扩展支持。
hangfire 的架构
Getting Started — Hangfire Documentation
快速开始
先来搭建一个最基本的 Hangfire Server
Hangfire Server
使用 nuget 安装 Hangfire package
Install-Package Hangfire
存储层方面,Hangfire 支持多种数据库,这里我们使用 Redis。
Install-Package Hangfire.Redis.StackExchange.StrongName
Program.cs 中注册 hangfire 服务
var builder = WebApplication.CreateBuilder(args);
//The `Hangfire.AspNetCore` integration package adds an extension method to register all the services, their implementation, as well as logging and a job activator
builder.Services.AddHangfire(x =>
{
x.UseRedisStorage("127.0.0.1:6379",new Hangfire.Redis.RedisStorageOptions
{
Db=11,
Prefix = "Hangfire:"
});
});
// Add the processing server as IHostedService
builder.Services.AddHangfireServer();
var app = builder.Build();
app.Run();
至此,一个基本的 hangfire server 就已经实现。接下来我们再简单实现一个 Hangfire Client。
Hangfire Client
安装 nuget package
Install-Package Hangfire.Core
Install-Package Hangfire.Redis.StackExchange.StrongName
配置存储层地址
GlobalConfiguration.Configuration.UseRedisStorage("127.0.0.1:6379", new Hangfire.Redis.RedisStorageOptions
{
Db = 11,
Prefix = "Hangfire:"
});
便可以愉快地开始创建 Job,让 Hangfire 服务器执行任务:
BackgroundJob.Enqueue(
() => Console.WriteLine($"Fire-and-forget at {DateTime.Now.ToString("G")}"));
var jobId = BackgroundJob.Schedule(
() => Console.WriteLine($"Delayed at {DateTime.Now.ToString("G")}"),
TimeSpan.FromSeconds(3));
RecurringJob.AddOrUpdate(
"myrecurringjob",
() => Console.WriteLine("Recurring!"),
"0/2 * * * * ? "); //Cron
BackgroundJob.ContinueJobWith(
jobId,
() => Console.WriteLine($"Continuation at {DateTime.Now.ToString("G")}"));
完成创建任务后,我们可以看到控制台中输出了完成任务的情况。
配置 UI 界面
可视化管理界面是 Hangfire 不同于其他任务调度框架的亮点之一。
Hangfire Dashboard
var builder = WebApplication.CreateBuilder(args);
//Add Hangfire services.
builder.Services.AddHangfire(x =>
{
x.UseRedisStorage("127.0.0.1:6379",new Hangfire.Redis.RedisStorageOptions
{
Db=11,
Prefix = "Hangfire:"
});
});
// Add the processing server as IHostedService
builder.Services.AddHangfireServer();
var app = builder.Build();
//启用hangfire dashboard中间件
app.UseHangfireDashboard();
app.Run();
再次使用 Client 创建任务,现在我们可以在 Dashboard 中看到任务的执行情况。并且,还可以使用 .UseDashboardMetric()
去添加需要的报表。
可视化创建任务
除此之外我们还将添加两个扩展 Hangfire.Console、Hangfire.Dashboard.Management
Install-Package Hangfire.Console
Install-Package Hangfire.Dashboard.Management
.UseConsole()
:可以输出 Console.Write 的 log 到 Hangfire 的任务页面,支持文案颜色的修改。还支持任务进度条的展示。
.UseManagementPages()
:可视化创建任务的关键扩展,在默认仪表板中提供一个 Management 页面,可以手动在管理界面创建任务。
先在 server 中开启这两个扩展
builder.Services.AddHangfire(x =>
{
var connectionString = builder.Configuration.GetConnectionString("Redis");
x.UseRedisStorage(connectionString, redisOptions);
x.UseDashboardMetric(DashboardMetrics.ServerCount)//服务器数量
.UseConsole()
.UseManagementPages(Assembly.Load("HangFireDemo.Jobs")); //加载程序集
});
想要使用 ManageMentPage 需要实现对应的配置类,如下:
[ManagementPage("侧边菜单栏的标题")]
public class TestJobC
{
[Hangfire.Dashboard.Management.Support.Job] //必须要声明这个属性
[DisplayName("任务标题")]
[Description("任务描述")]
[AutomaticRetry(Attempts = 0)] //重试次数
[DisableConcurrentExecution(90)]//禁用并行执行
public void Test(PerformContext context, IJobCancellationToken token,
[DisplayData("Output Text", "Enter text to output.")] string outputText,
[DisplayData("Bool类型参数", "Bool展示名称")] bool repeat,
[DisplayData("Test Date", "Enter date")] DateTime testDate)
{
context.WriteLine(testDate + ":" + outputText);
}
}
使用这个可视化 UI,除了看到任务执行的统计信息外,我们还能在 management 页面去执行任务,这就是 Hangfire 的方便之处。
此外,GitHub 上还提供了许多开源扩展:Extensions — Hangfire Core, 可以按需加入项目中。
总结
相比较于之前使用.NET Framework 创建 Hangfire 的项目,在.NET 6 上创建 Hangfire 的项目无疑是更简洁、更快速。而且 ASP.NET Core“基于云”、“跨平台”的特性让应用的部署有更多的可能性。