项目中使用Hangfire已经快一年了,期间经历过很多次的试错及升级优化,才达到现在的稳定效果。趁最近不是太忙,自己在github上做了个案列,也是拿来跟大家分享下,案例是从项目里剥离出来的,有兴趣的可以访问 这里.
什么是Hangfire
Hangfire 是一个开源的.NET任务调度框架,目前1.6+版本已支持.NET Core。个人认为它最大特点在于内置提供集成化的控制台,方便后台查看及监控:
另外,Hangfire包含三大核心组件:客户端、持久化存储、服务端,官方的流程介绍图如下:
从图中可以看出,这三个核心组件是可以分离出来单独部署的,例如可以部署多台Hangfire服务,提高处理后台任务的吞吐量。关于任务持久化存储,支持Sqlserver,MongoDb,Mysql或是Redis等等。
Hangfire基础
基于队列的任务处理(Fire-and-forget jobs)
基于队列的任务处理是Hangfire中最常用的,客户端使用BackgroundJob
类的静态方法Enqueue
来调用,传入指定的方法(或是匿名函数),Job Queue等参数.
var jobId = BackgroundJob.Enqueue(
() => Console.WriteLine("Fire-and-forget!"));
在任务被持久化到数据库之后,Hangfire服务端立即从数据库获取相关任务并装载到相应的Job Queue下,在没有异常的情况下仅处理一次,若发生异常,提供重试机制,异常及重试信息都会被记录到数据库中,通过Hangfire控制面板可以查看到这些信息。
延迟任务执行(Delayed jobs)
延迟(计划)任务跟队列任务相似,客户端调用时需要指定在一定时间间隔后调用:
var jobId = BackgroundJob.Schedule(
() => Console.WriteLine("Delayed!"),
TimeSpan.FromDays(7));
定时任务执行(Recurring jobs)
定时(循环)任务代表可以重复性执行多次,支持CRON
表达式:
RecurringJob.AddOrUpdate(
() => Console.WriteLine("Recurring!"),
Cron.Daily);
延续性任务执行(Continuations)
延续性任务类似于.NET中的Task
,可以在第一个任务执行完之后紧接着再次执行另外的任务:
BackgroundJob.ContinueWith(
jobId,
() => Console.WriteLine("Continuation!"));
其实还有批量任务处理,批量任务延续性处理(Batch Continuations),但这个需要商业授权及收费。在我看来,官方提供的开源版本已经基本够用。
与quartz.net对比
在项目没有引入Hangfire之前,一直使用的是Quartz.net。个人认为Quartz.net在定时任务处理方面优势如下:
支持秒级单位的定时任务处理,但是Hangfire只能支持分钟及以上的定时任务处理
原因在于Hangfire用的是开源的NCrontab组件,跟linux上的crontab指令相似。
更加复杂的触发器,日历以及任务调度处理
可配置的定时任务
但是为什么要换Hangfire? 很大的原因在于项目需要一个后台可监控的应用,不用每次都要从服务器拉取日志查看,在没有ELK的时候相当不方便。Hangfire控制面板不仅提供监控,也可以手动的触发执行定时任务。如果在定时任务处理方面没有很高的要求,比如一定要5s定时执行,Hangfire值得拥有。抛开这些,Hangfire优势太明显了:
持久化保存任务、队列、统计信息
重试机制
多语言支持
支持任务取消
支持按指定
Job Queue
处理任务服务器端工作线程可控,即job执行并发数控制
分布式部署,支持高可用
良好的扩展性,如支持IOC、Hangfire Dashboard授权控制、Asp.net Core、持久化存储等
说了这么多的优点,我们可以有个案例,例如秒杀场景:用户下单->订单生成->扣减库存,Hangfire对于这种分布式的应用处理也是适用的,最后会给出实现。
Hangfire扩展
重点说一下上面提到的第8点,Hangfire扩展性
,大家可以参考 这里,有几个扩展是很实用的.
Hangfire Dashborad日志查看
Hangfire.Console提供类似于console-like的日志体验,与Hangfire dashboard集成: