如果在单项目中使用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. 客户端和服务端可以按照实际情况来分析是否需要拆分(因为在客户端创建的任务,这个任务方法体必须同时存在于客户端和服务端中)