Hangfire简单分布式
今晚研究了下,发现这个Hangfire实在是比Quartz.Net灵活好多。赶紧笔记下~~
开发环境
VS 2019 / .NET Framework 4.6.2
架构图
可以有很多Client,设置不同的Queue后来分配任务。
Queue队列概念
Hangfire中的队列是用于区分任务的管道,在程序入口的 BackgroundJobServerOptions 中可以配置客户端能接受的队列。
这样可以方便的区分开任务,每个服务器可以独立处理指定任务。这里简单理解为类似MQ的感觉吧。
Queue的名称需要注意:小写字母,数字,下划线和破折号。
Demo构建
分别创建了两个项目:
- ConsoleApp Job的具体执行方法和BackgroundJobServer放在这里
- ConsoleWeb Hangfire的Web控制台放在这里,项目是MVC框架
ConsoleApp 需要如下Nuget包:
Install-Package Hangfire
Install-Package Hangfire.Redis.StackExchange
Install-Package Hangfire.Dashboard.Management
Install-Package Hangfire.Console
ConsoleWeb 需要如下Nuget包:
Install-Package Hangfire
Install-Package Hangfire.Redis.StackExchange
Install-Package Hangfire.Dashboard.Management
Install-Package Hangfire.Console
ConsoleApp
Program.cs
// Redis 配置
var redisOption = new RedisStorageOptions()
{
Db = 12,
Prefix = "hangfire:"
};
// 使用Redis存储
GlobalConfiguration.Configuration
.UseRedisStorage("127.0.0.1", redisOption)
.UseConsole();
var option = new BackgroundJobServerOptions() {ServerName = "666", Queues = new[] {"wb"}};
using (var server = new BackgroundJobServer(option))
{
Console.WriteLine("Hangfire Server started. Press any key to exit...");
Console.ReadKey();
}
// 阻止控制台关闭
Thread.Sleep(Timeout.Infinite);
另外创建一个测试的调用方法
[ManagementPage("演示")]
public class JobCenter
{
[DisplayName("主方法")]
[Queue("wb")]
[Hangfire.Dashboard.Management.Support.Job]
public static void JobA(PerformContext context = null)
{
Console.WriteLine(DateTime.Now);
context.WriteLine("嗯??");
Thread.Sleep(1000);
context.WriteLine("睡醒了");
}
}
如果需要在控制台中看得见方法,需要在方法的Class上增加修饰器,并且使用"DisplayName"来定义名称。
JobA中的 PerformContext 是 Hangfire.Console 的拓展功能,可以方便的输出信息到web中。
ConsoleWeb
ConsoleWeb需要引用客户端项目,或者直接将Dll放到目录下读取也可以。
Startup.cs 代码
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddHangfire(config => config
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseColouredConsoleLogProvider()
.UseDashboardMetric(Hangfire.Dashboard.DashboardMetrics.ServerCount)//服务器数量
.UseDashboardMetric(Hangfire.Dashboard.DashboardMetrics.RecurringJobCount)//定时任务
.UseDashboardMetric(Hangfire.Dashboard.DashboardMetrics.RetriesCount)//重试次数
.UseDashboardMetric(Hangfire.Dashboard.DashboardMetrics.EnqueuedAndQueueCount)//队列数量
.UseDashboardMetric(Hangfire.Dashboard.DashboardMetrics.ScheduledCount)//计划
.UseDashboardMetric(Hangfire.Dashboard.DashboardMetrics.ProcessingCount)//执行中
.UseDashboardMetric(Hangfire.Dashboard.DashboardMetrics.SucceededCount)//成功的作业
.UseDashboardMetric(Hangfire.Dashboard.DashboardMetrics.FailedCount)//失败
.UseDashboardMetric(Hangfire.Dashboard.DashboardMetrics.DeletedCount)//已删除的任务
.UseDashboardMetric(Hangfire.Dashboard.DashboardMetrics.AwaitingCount)//等待中
.UseConsole()// Hangfire.Console 需要web输出消息则要引用他
.UseRedisStorage("127.0.0.1", new Hangfire.Redis.RedisStorageOptions { Db = 12, Prefix = "hangfire:" })
.UseManagementPages(cc => cc.AddJobs(() => { return GetModuleTypes(); }))//任务管理工具
);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHangfireDashboard();
}
/// <summary>
/// 取出所有的 ManagementPage
/// </summary>
/// <returns></returns>
private static Type[] GetModuleTypes()
{
var assemblyList = new List<Assembly>()
{
Assembly.Load("ConsoleApp1")// 获取对象
};
var moduleTypes = assemblyList.SelectMany(f =>
{
try
{
return f.GetTypes();
}
catch (Exception)
{
return new Type[] { };
}
}).ToArray();
return moduleTypes;
}
}
其他的无用代码暂时删除了
执行项目后可以在这里看见方法了
这里可以设定任务怎么执行
- 列队执行 => BackgroundJob.Enqueue();
- 定时执行 => BackgroundJob.Schedule();
- 延时执行 => BackgroundJob.ContinueWith();
- 重复执行 => RecurringJob.AddOrUpdate();
重复执行还内置了Cron的生成工具,简直不要太爽,但是Hangfire并没支持到秒级别。
如果手工写秒级计划任务,会发现并不会按照间隔来执行。
创建作业
通过向导创建重复执行任务后就能在“周期性作业”中看见这个任务了
在这里可以手工执行,删除和暂停任务等。
在“作业”Tab中可以查看到历来执行的任务记录。