.NET Core开源组件:后台任务利器之Hangfire

1 篇文章 0 订阅

.NET Core开源组件:后台任务利器之Hangfire

1.注入Hnagfire服务

services.AddHangfire(x => x.UseSqlServerStorage("<connection string>"));

本地用到的

//设置Job数据库
            var taskConnStr = config.Get("Data:TaskConnection:Connectionstring");
            GlobalConfiguration.Configuration.UseSqlServerStorage(taskConnStr);

2.可选配置

启动Hangfire服务和对应的web面板如下:

 app.UseHangfireServer();//启动Hangfire服务
 app.UseHangfireDashboard();//启动hangfire面板

本地

//控制台
            app.UseHangfireDashboard()
               //创建job执行队列
               .UseHangfireServer(new BackgroundJobServerOptions()
               {
                   Queues = new[] { "default", "aqi" }
               });

2.1 配置任务属性

var jobOptions = new BackgroundJobServerOptions
{
       Queues = new[] { "test","default" },//队列名称,只能为小写
       WorkerCount = Environment.ProcessorCount * 5, //并发任务数
       ServerName="hangfire1",//服务器名称
 };
app.UseHangfireServer(jobOptions);

Queues 要处理的队列列表
对于有多个服务器同时连接到数据库,Hangfire会认为他们是分布式中的一份子。现实中不同服务器往往存在着差异,这个时候就需要合理配置服务器(应用)的处理队列,举两个例子:
1.对于服务器性能差异的处理,有100个A任务和50个B任务需要处理,假设A服务器的性能是B服务器的两倍,如果不配置队列,那么会平分任务给两个服务器。如果我们只让B服务器处理B任务,而A服务器同时处理两种任务,这样B就能减少一些压力。

2.对于服务器能力差异的处理,假设A服务器能处理A和B两种任务,B服务器只能处理B任务(没有处理A任务的方法或对象),如果不配置队列,默认会让B也执行A任务,从而产生错误。反面一想,如果A服务器和B服务器都有共同的接口,B服务器不实现接口的方法,发起一个专属于A服务器队列的任务,而A服务器通过注入实现接口的方法,可以达到传递任务的效果。

WorkerCount 并发任务数,超出并发数将等待之前的任务完成
默认的并发任务数是线程(cpu)的5倍,如果IO密集型任务多而CPU密集型的任务少,可以考虑调高并发任务数。

以上是我用到的,当然还有其他配置参数等着你去开发。

2.2.配置访问权限

在实际生产中,我们可能不希望任何人都可以访问面板,或暂停执行某些任务,这时就需要重写面板的权限了。默认情况下,只有本地访问权限才能使用Hangfire仪表板。所以需要重写控制面板,以便远程访问。

 var options = new DashboardOptions
{
    Authorization = new[] { new HangfireAuthorizationFilter() }
};
app.UseHangfireDashboard("/hangfire", options);
public class HangfireAuthorizationFilter : IDashboardAuthorizationFilter
{
        //这里需要配置权限规则
        public bool Authorize(DashboardContext context)
        {
            return true;
        }
}

任务类型


Fire-and-forget 直接将任务加入到待执行任务队列

Fire-and-forget 的调用方法极其简单。正如您从 :doc:`快速开始<../quick-start>` 一节中了解到,您只需要传递一个具有相应方法和参数的lambda表达式:

BackgroundJob.Enqueue(() => Console.WriteLine("Hello, world!"));

Enqueue 方法不会立即调用目标方法,而是运行以下步骤:

  1. 序列化目标方法及其所有参数。
  2. 根据序列化的信息创建一个新的后台任务。
  3. 将后台任务保存到持久化存储。
  4. 将后台任务入队。

 

执行这些步骤后, BackgroundJob.Enqueue 方法立即返回结果。轮到另一个Hangfire组件,:doc:`Hangfire Server <../background-processing/processing-background-jobs>` 将会从持久化存储中检查到队列中有后台任务后如期执行。

队列任务由专门的工作线程处理。每个worker将如下述流程执行任务:

  1. 获取一个任务,并对其他worker隐藏该任务。
  2. 执行任务及其所有的扩展过滤器。
  3. 从队列中删除该任务。

因此,只有处理成功后才能删除该任务。即使一个进程在执行期间被终止,Hangfire将执行补偿逻辑来保证每个任务都被处理。

每种持久存储各有各自的步骤和补偿逻辑机制:

  • SQL Server 使用常规SQL事务,因此在进程终止的情况下,后台作业ID立即放回队列。
  • MSMQ 使用事务队列,因此不需要定期检查。入队后几乎立即获取作业。
//创建任务依赖注入容器
            var service = IocExtensions.CreateJobIoc();

            service.AddSingleton<IMqOperation>(x => new MsmqOperation(@".\Private$\MapuniJob_{0}"));
  • Redis 实现使用阻塞的 BRPOPLPUSH 命令,因此与MSMQ一样立即获取作业。但是在进程终止的情况下,只有在超时到期后(默认为30分钟)才重新排队。

Delayed 在当前时间后的某个时间将任务加入到待执行任务队列
Recurring 周期性任务,每一个周期就将任务加入到待执行任务队列
Continuations 顾名思义,继续执行任务

1.简单入门

using (var connection = JobStorage.Current.GetConnection())
 {
       var storageConnection = connection as JobStorageConnection;
       if (storageConnection != null)
        {
            //立即启动
           var jobId = BackgroundJob.Enqueue(()=>Console.WriteLine("Fire-and-forget!"));
       }
 }

当然,不仅仅只有静态方法可以执行,Hangfire的任务也是支持.net core的依赖注入的,会构造一个对象并执行对应的方法。

BackgroundJob.Enqueue<SomeClass>(i => i.SomeMethod(someParams))

2.进阶功能

2.1设置任务队列

[Queue("test")]
public void TestQueue()
{
}

对于非周期任务,只需要在执行的方法添加Queue的特性就能指定该任务让特定的队列服务器处理。
而周期任务,则需要先声明:

RecurringJob.AddOrUpdate(() => Console.WriteLine("Recurring!"),Cron.Daily,queue:"test");

Hangfire支持自定义过滤器,可以对任务在创建时、执行中、执行后等等状态执行特定特定的操作。

//特定方法过滤器
[LogEverything]
public static void Send() { 
}
//全局过滤器
GlobalJobFilters.Filters.Add(new LogEverythingAttribute());

四.中文文档

hangfire是一个不错的开源后台任务组件,官方没有中文文档,所以简单地用谷歌机翻修改了一下。

文档在github的地址:https://github.com/jonechenug/Hangfire-Chinese-Doc

docker运行并访问本地8080端口:

docker run --restart always  --name hangfire -d -p 8080:80 daocloud.io/koukouge/hangfirezhdoc

C#-初识Hangfire

引用命名空间。

using Hangfire;
  • Fire-and-forget jobs(基于队列的任务处理)
var jobId = BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget!"));

 

  • Delayed jobs(延迟任务执行)
  • var jobId = BackgroundJob.Schedule(() => Console.WriteLine("Delayed!"), TimeSpan.FromDays(7));
  • Recurring jobs(定时任务执行)
    RecurringJob.AddOrUpdate(() => Console.WriteLine("Recurring!"), Cron.Daily);
  • Continuations(延续性任务执行)
    BackgroundJob.ContinueWith(jobId , () => Console.WriteLine("Continuation!"));
  • Batches(批处理) | Pro 版
    var batchId = BatchJob.StartNew(x =>
    {
        x.Enqueue(() => Console.WriteLine("Job 1"));
        x.Enqueue(() => Console.WriteLine("Job 2"));
    })
  • Batch Continuations(延续性批处理) | Pro 版

 

备注:

1.每个Hangfire服务器都有一个唯一的标识符,由两部分组成,后一部分是处理同一台机器上多个服务器的进程ID。前一部分是服务器名称,默认为计算机名称,用于处理不同计算机的唯一性。由于默认值仅在进程级别上提供唯一性,因此如果要在同一进程中运行不同的服务器实例,那么你就需要如上所示进行手动处理,上面实例就是手动new NewGuid。
2.对于Queues 如果开发者不自行配置的话,hangfire默认是只增加一个名为‘defult’的队列,既意为若未进行配置,就一个队列可选Queues[0]。
3.队列名称参数必须仅包含小写字母,数字和下划线字符。
4.要将作业放入不同的队列,方法一是在创建作业时选择队列,二是在方法上使用QueueAttribute类。
5.hangfire将首先从关键队列中获取作业,然后从默认队列中获取作业
6.关于WorkerCount ,有文章称其默认值是CPU核心数*5,但可能是被官网资料的代码示例误导WorkerCount = Environment.ProcessorCount * 5,我的主机为I5-8400,6核心,Environment.ProcessorCount为6,默认值为20。不过因

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值