如果在单项目中使用Hangfire可以比较无脑的玩,如果从架构层面考虑Hangfire那需要明确如何拆分
-- Hangfire 结构
1. 数据库
Hangfire 可采用 MySQL、MSSQL、Redis 等多种数据库作为数据存储媒介
只要指向数据源,则Hangfire会自动创建配套的数据表
2. 客户端
Hangfire 的客户端层只负责创建任务,在配置好 HangFire 数据库连接后,创建任务的时候 HangFire 会自动将任务序列化并存储到数据
-- 1. 立即执行的一次性任务
var jobId = BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget!"));
-- 2. 延迟执行的一次性任务
var jobId = BackgroundJob.Schedule(() => Console.WriteLine("Delayed!"), TimeSpan.FromDays(7));
-- 3. 循环执行任务,每隔多久执行一次
RecurringJob.AddOrUpdate("myrecurringjob", () => Console.WriteLine("Recurring!"), Cron.Daily);
-- 4. 延续的一次性任务,前一个任务完成后才会执行
-- 这里的 JobId = 上一个任务的Id
BackgroundJob.ContinueJobWith(jobId, () => Console.WriteLine("Continuation!"));
3. 服务端
从 HangFire 数据表中读取客户端创建的任务然后开线程并行执行,任务之间不冲突。(服务端可宿主在Windows服务、控制台程序、IIS中…)
-- IIS 默认 20 分钟没有人访问会停止,HangFire作业服务也会停止,所以如果是 IIS 必须进行相应的配置来提高稳定性
-- nuget 只需要获取 Hangfire.SqlServer 就行,如果低版本的未含有 Hangfire.Core 则需要另外获取
using Hangfire;
using Hangfire.SqlServer;
-- Web 项目中使用
public void ConfigureServices(IServiceCollection services)
{
services.AddHangfire(x => x.UseSqlServerStorage("数据库链接字符串"));
services.AddHangfireServer();
......
}
-- Windows 服务
public partial class Service1 : ServiceBase
{
private BackgroundJobServer _server;
public Service1()
{
InitializeComponent();
/* 记得在配置文件中添加数据库连接字符串 */
GlobalConfiguration.Configuration.UseSqlServerStorage("数据库链接字符串");
}
protected override void OnStart(string[] args)
{
_server = new BackgroundJobServer();
/* 可以在BackgroundJobServer实例化之后的任意位置添加任务 */
}
protected override void OnStop()
{
_server.Dispose();
}
}
4. 仪表盘
展示作业列表执行状态和结果等相关信息
-- 只支持 Web 应用程序
-- 使用仪表盘代码
var options = new DashboardOptions
{
/* 这里可以添加过滤器来限制访问规则 */
Authorization = new[] { new HangfireAuthorizationFilter() }
};
app.UseHangfireDashboard("/hangfire", options);
-- 如果需要权限限制,则增加 Filter 类
public class HangfireAuthorizationFilter : IDashboardAuthorizationFilter
{
/* 这里需要配置权限规则 */
public bool Authorize(DashboardContext context)
{
return true;
}
}
理解了以上的概念,那在实际架构中
1. 仪表盘可以独立出来作为单独的 Web 应用程序,这个项目几乎不会有任何改动
2. 客户端和服务端可以按照实际情况来分析是否需要拆分(因为在客户端创建的任务,这个任务方法体必须同时存在于客户端和服务端中)