Hangfire 是什么?

Hangfire 是一个定时任务的管理后台,它拥有定时任务功能和及其相关的管理后台界面。Hangfire 原生使用 .NET 开发的,同时支持 .NET.NET Core 框架,所以可同时运行在 Windows 和 非 windows 平台上。

Hangfire 可以做什么?

其实上面已经提到了,可以像 Quartz.NET 一样自定义定时任务,但 Hangfire 提供了任务的 Web 管理界面,所以你可以很方便的查看任务状态管理任务,你也不需要远程登录 Windows Server 桌面重启或停止任务了,方便了很多,同时它提供持久化,即使程序挂掉或重启,上次未被执行或没执行完成的任务会继续执行。

是不是有点小期待,想知道 Hangfire 怎么用,别急下面就介绍如何使用,如果你一点都不期待,你也可以稍微花些许时间看一眼,没准也许你会不经意喜欢上它。好了,废话不说了,重点马上来!

Hangfire 如何使用?

这次我打算依旧使用 ASP .NET Core 作为本次的例子开发框架,例子代码地址会放在文章最后。在终端输入以下代码创建项目:

mkdir ~/Development/HangfireJobs && cd ~/Development/HangfireJobs
dotnet new sln
dotnet new mvc -n HangfireJobsApp
dotnet sln add ./HangfireJobsApp/HangfireJobsApp.csproj
cd ./HangfireJobsApp
dotnet restore
dotnet build
dotnet run
...

现在一个基本的 Asp .Net Core MVC 项目在你本地创建并运行起来了,如下图所示:



接下来在终端输入以下代码,来添加Hangfire相关的包

dotnet add package HangFire --version 1.6.19
dotnet add package HangFire.Redis.StackExchange --version 1.7.2
dotnet build

这里任务持久化使用 Redis,所以添加了 HangFire.Redis.StackExchange nuget包,这是个三方的不是原作者开发的,原生的 Redis 包需要商业收费,但我觉得这个包暂时够用了。接下来,使用 VSCode 打开 Startup.cs 文件,敲入写入以下代码:

public void ConfigureServices(IServiceCollection services)
{
// 自动生成代码忽略 // 注入Hangfire
services.AddHangfire(cfg=>{
cfg.UseRedisStorage(Configuration.GetConnectionString("Hangfire"));
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// 自动生成代码忽略 // 启用Hangfire
app.UseHangfireServer();
app.UseHangfireDashboard();
}

最后在appsettings.json文件,加入以下配置:

{
// ... "ConnectionStrings":{
"Hangfire":"127.0.0.1:6379"
}
}

因为持久化用 Redis,所以这里需要你配置 Redis 地址,那么运行你的项目,然后在浏览器上输入地址



到这里,你已经完成了大部分工作,剩下的就是实现具体任务啦。

不过别急,我们先看看 Hangfire 的任务类型。

Hangfire有三种类型的任务:FAF(fire adn forget)即一次性任务,计划任务(在某个时间点执行一次),还有就是最常用的周期性任务,可以设置某个时刻重复执行。还是用代码展示吧。

...
// 立即执行的单次任务
BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget"));
// 创建计划任务,5分钟后执行
BackgroundJob.Schedule(() => Console.WriteLine("Delayed"), TimeSpan.FromMinutes(5));
// 创建周期性任务,每隔2分钟执行一次
RecurringJob.AddOrUpdate("JobA", () => Console.WriteLine("Recurred"), Cron.MinuteInterval(2));
// 创建周期性任务,每天21:10执行,
RecurringJob.AddOrUpdate("JobB", () => Console.WriteLine(DateTimeOffset.Now), "10 21 * * *");
// 创建周期性任务,每天21:10执行
RecurringJob.AddOrUpdate("JobC", () => Test(), "10 21 * * *", TimeZoneInfo.Local);
...
public void Test()
{
Console.WriteLine(DateTimeOffset.Now);
}

在代码里,你发现周期任务我多列了2个,而且貌似执行时间都相同,然而还是不同的。你需要注意时区的问题,Recurring 添加任务时默认是UTC-0时区,所以当你写代码创建任务时,要注意是否需要指定时区,否则任务可能不会按照你预期的时间执行。

其实这段代码,还有些东西需要注意,也许你注意到了,就是在控制台输出的时间,在最后两个任务是不一致的,你或许会说是因为时区问题,即使改成同一时区输出结果也还是不同,你可以想想为什么。

JobActivator

上面的创建任务的例子确实有些简单了,你想要更优雅的创建任务,比如通过依赖注入的方式。别急 Hangfire 已经提供了解决方法,没错就是 JobActivator,它允许你通过依赖注入这样更方便的方式调用你自定义的任务。

在这个例子里,我分别创建三个类:HFSimpleJob,HFJobActivator,HFJobActivatorScope,代码如下:

// HFSimpleJob.cs
...
public class HFSimpleJob
{
int counter = 0;
public void Run()
{
counter++;
Console.WriteLine($"当前时间是:{DateTimeOffset.Now},当前计数:{counter}");
}
}
// HFJobActivator.cs
...
public class HFJobActivator : JobActivator
{
readonly IServiceScopeFactory _serviceScopeFactory;
public HFJobActivator(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = serviceScopeFactory;
}
public override JobActivatorScope BeginScope(JobActivatorContext context)
{
return new HFJobActivatorScope(_serviceScopeFactory.CreateScope());
}
}
// HFJobActivatorScope.cs
public class HFJobActivatorScope : JobActivatorScope
{
IServiceScope _serviceScope;
public HFJobActivatorScope(IServiceScope serviceScope)
{
if (serviceScope == null) throw new ArgumentNullException(nameof(serviceScope));
_serviceScope = serviceScope;
}
public override object Resolve(Type type)
{
return _serviceScope.ServiceProvider.GetService(type);
}
public override void DisposeScope()
{
_serviceScope.Dispose();
}
}

HFSimpleJob就是一个简单的模拟业务的任务类,就不细说了,重点说说后面两个。HFJobActivator这个类继承自 JobActivator ,它用来在任务执行前实例化你注入的任务类的 Activator,而 HFJobActivatorScope 继承自 JobActivatorScope,这个类的作用就是调用 IOC 容器实例化之前注入的类。

OK,现在再加上如下代码:

public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<HFSimpleJob>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)
{
.... // 添加自定义依赖注入相关类
GlobalConfiguration.Configuration.UseActivator(new HFJobActivato(serviceProvider.GetService<IServiceScopeFactory>()));
// 启用Hangfire
app.UseHangfireServer();
app.UseHangfireDashboard(); // 依赖注入
RecurringJob.AddOrUpdate<HFSimpleJob>("JobIOCA", p => p.Run(), "*/2 * * **");
}

编译运行代码,就可以看到类似下面截图的内容了,最后一个就是使用依赖注入的方式创建的任务:



是不是觉得这样写,没感觉简单多少,这里只是简单举例讲述怎么用,需要自己具体问题具体分析。我这里写一个我的用例,我先定义任务接口,然后所有的业务任务类都实现这个接口,然后使用反射将这些类通过 IOC 的方式批量注入,这样后面新增其它业务的任务,就无须关注业务以外的任务注册调用的代码了,只要实现那个接口测试编译通过即可,这样就简单了很多。这里就不写怎么实现了,你可以自己想想如何,我会把这部分功能放在Demo里。

Hangfire初探的更多相关文章

  1. 开源的.NET定时任务组件Hangfire解析

    项目慢慢就要开工了,很多园友都在问这个事情,看来大伙对这事很上心啊,事情需要一步步的来,尽量写出一个我们都满意的项目.以前每次在博客前面都会扯淡一下,不过很多人都抱怨这样做不好,加上我这人扯淡起来就停 ...

  2. NET定时任务组件Hangfire

    开源的.NET定时任务组件Hangfire解析 项目慢慢就要开工了,很多园友都在问这个事情,看来大伙对这事很上心啊,事情需要一步步的来,尽量写出一个我们都满意的项目.以前每次在博客前面都会扯淡一下,不 ...

  3. Hangfire项目实践分享

    Hangfire项目实践分享 目录 Hangfire项目实践分享 目录 什么是Hangfire Hangfire基础 基于队列的任务处理(Fire-and-forget jobs) 延迟任务执行(De ...

  4. ABP文档 - Hangfire 集成

    文档目录 本节内容: 简介 集成 Hangfire 面板授权 简介 Hangfire是一个综合的后台作业管理器,可以在ABP里集成它替代默认的后台作业管理器,你可以为Hangfire使用相同的后台作业 ...

  5. 初探领域驱动设计(2)Repository在DDD中的应用

    概述 上一篇我们算是粗略的介绍了一下DDD,我们提到了实体.值类型和领域服务,也稍微讲到了DDD中的分层结构.但这只能算是一个很简单的介绍,并且我们在上篇的末尾还留下了一些问题,其中大家讨论比较多的, ...

  6. CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探

    CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码 ...

  7. ABP源码分析三十九:ABP.Hangfire

    ABP对HangFire的集成主要是通过实现IBackgroundJobManager接口的HangfireBackgroundJobManager类完成的. HangfireBackgroundJo ...

  8. 从273二手车的M站点初探js模块化编程

    前言 这几天在看273M站点时被他们的页面交互方式所吸引,他们的首页是采用三次加载+分页的方式.也就说分为大分页和小分页两种交互.大分页就是通过分页按钮来操作,小分页是通过下拉(向下滑动)时异步加载数 ...

  9. JavaScript学习(一) —— 环境搭建与JavaScript初探

    1.开发环境搭建 本系列教程的开发工具,我们采用HBuilder. 可以去网上下载最新的版本,然后解压一下就能直接用了.学习JavaScript,环境搭建是非常简单的,或者说,只要你有一个浏览器,一个 ...

随机推荐

  1. Jenkins的job执行arquilian test时总是报JBoss启动失败错误

    我的Jenkins环境是一个Master+一个slave,Job的执行主要由slave来进行.Master只负责调度. slave上安装有JDK7.JDK8.slave agent用的是java we ...

  2. [工具教程] HBuilder调试夜神安卓模拟器方法(该方法真实有效)

    HBuilder调试夜神安卓模拟器方法 现在开发手机app的IDE很多,今天我就以我个人开发使用的HBuider开发工具讲一下手机app开发调试.HBuider支持真机调试,这个比较简单,只要安装好手 ...

  3. CopyOnWriteArrayList对比ArrayList

    ArrayList非线程安全,CopyOnWriteArrayList线程安全 ArrayList添加元素的时候内部会预先分配存储空间,CopyOnWriteArrayList每次添加元素都会重新co ...

  4. ojdbc14_g.jar与ojdbc14.jar区别

    在低级JDK版本1.2与1.3中使用的驱动,class12.jar,虽然实际上在1.4,1.5中使用大部分情况也是OK的 ojdbc14.jar (1,545,954 bytes) - classes ...

  5. 51nod 1515 明辨是非 [并查集+set]

    今天cb巨巨突然拿题来问,感觉惊讶又开心,希望他早日康复!!坚持学acm!加油! 题目链接:51nod 1515 明辨是非 [并查集] 1515 明辨是非 题目来源: 原创 基准时间限制:1 秒 空间 ...

  6. XXE攻防——XML外部实体注入

    XXE攻防——XML外部实体注入 转自腾讯安全应急响应中心 一.XML基础知识 XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据.定义数据类型,是一种允许用户对自己的标记语言进行定义的 ...

  7. sql的寫法,推薦的寫法,全文索引提高類似like查詢的效率

    說明:logistics_detail表中每個deliver_id可能對應多個loginticsType,但是我們只要獲取最大的那一個. SELECT dm.delivery_code,dm.deli ...

  8. mybatis会对多参数方法进行特殊处理

    例如:查询id=1,name=tom的一条数据 查询接口: User getUserByIdAndName(Integer id,String name); // <?xml version=& ...

  9. 论文笔记 | A Closer Look at Spatiotemporal Convolutions for Action Recognition

    ( 这篇博文为原创,如需转载本文请email我: leizhao.mail@qq.com, 并注明来源链接,THX!) 本文主要分享了一篇来自CVPR 2018的论文,A Closer Look at ...

  10. java中StringBuffer与String、StringBuilder的区别

    在java中我们经常可以看到StringBuffer和String的用法,但是我自己在使用过程中,经常会将两者弄混淆,今天我们就来了解一下两者的区别: 我们首先来看一下我们的官方API中的简单介绍: ...