Hangfire初探
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初探的更多相关文章
- 开源的.NET定时任务组件Hangfire解析
项目慢慢就要开工了,很多园友都在问这个事情,看来大伙对这事很上心啊,事情需要一步步的来,尽量写出一个我们都满意的项目.以前每次在博客前面都会扯淡一下,不过很多人都抱怨这样做不好,加上我这人扯淡起来就停 ...
- NET定时任务组件Hangfire
开源的.NET定时任务组件Hangfire解析 项目慢慢就要开工了,很多园友都在问这个事情,看来大伙对这事很上心啊,事情需要一步步的来,尽量写出一个我们都满意的项目.以前每次在博客前面都会扯淡一下,不 ...
- Hangfire项目实践分享
Hangfire项目实践分享 目录 Hangfire项目实践分享 目录 什么是Hangfire Hangfire基础 基于队列的任务处理(Fire-and-forget jobs) 延迟任务执行(De ...
- ABP文档 - Hangfire 集成
文档目录 本节内容: 简介 集成 Hangfire 面板授权 简介 Hangfire是一个综合的后台作业管理器,可以在ABP里集成它替代默认的后台作业管理器,你可以为Hangfire使用相同的后台作业 ...
- 初探领域驱动设计(2)Repository在DDD中的应用
概述 上一篇我们算是粗略的介绍了一下DDD,我们提到了实体.值类型和领域服务,也稍微讲到了DDD中的分层结构.但这只能算是一个很简单的介绍,并且我们在上篇的末尾还留下了一些问题,其中大家讨论比较多的, ...
- CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探
CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码 ...
- ABP源码分析三十九:ABP.Hangfire
ABP对HangFire的集成主要是通过实现IBackgroundJobManager接口的HangfireBackgroundJobManager类完成的. HangfireBackgroundJo ...
- 从273二手车的M站点初探js模块化编程
前言 这几天在看273M站点时被他们的页面交互方式所吸引,他们的首页是采用三次加载+分页的方式.也就说分为大分页和小分页两种交互.大分页就是通过分页按钮来操作,小分页是通过下拉(向下滑动)时异步加载数 ...
- JavaScript学习(一) —— 环境搭建与JavaScript初探
1.开发环境搭建 本系列教程的开发工具,我们采用HBuilder. 可以去网上下载最新的版本,然后解压一下就能直接用了.学习JavaScript,环境搭建是非常简单的,或者说,只要你有一个浏览器,一个 ...
随机推荐
- pc端配置详细 2017级机械设计新生 史浩然
品牌名称:SAMSUNG/三星 证书状态:有效 申请人名称:苏州三星电子电脑有限公司 型号:940X3K-K01 操作系统:window8.1 产品名 ...
- 105 + 106. Construct Binary Tree from Preorder and Inorder Traversal (building trees)
Given preorder and inorder traversal of a tree, construct the binary tree. Note: You may assume that ...
- OC NSMutableString的使用
#pragma mark 可变字符串的创建 void stringCreate() { // 预先分配10个字数的存储空间 NSMutableString *str = [[NSMutableStri ...
- 全屏轮播插件 fullPage.js应用(基础版兼容IE7, 背景图版兼容IE8)
/** * fullPage 1.4.5 * https://github.com/alvarotrigo/fullPage.js * MIT licensed * * Copyright (C) 2 ...
- 【[ZJOI2006]物流运输】
一直不会做,觉得这是一道神题 于是万般无奈下去借鉴抄了一下题解 发现这就是一道套路题 我们用\(dp[i]\)表示前\(i\)天的最小总花费,于是我们就可以用一个常规的老套路来做了 那就是枚举断点 我 ...
- Python re模块正则表达式
- css3中的变形 transform详解
一.变形-旋转 ratate()函数 通过指定的角度参数使元素相对原点进行旋转.它主要在二维空间内进行操作,设置一个角度值,用来指定旋转的幅度.如果这个值为正值,元素相对原点中心顺时针旋转:如果这 个 ...
- kettle maven 配置
<properties> <kettle.version>6.1.0.4-225</kettle.version> </properties> < ...
- cmd进入指定的文件夹
怎么利用cmd进入指定的文件夹呢? 1:win+r ——cmd 2:进入要到达的盘符 (比如我要进入d盘) 3:然后通过 cd d:\project 进入指定的文件夹
- HDU 2717 Catch That Cow(常规bfs)
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2717 Catch That Cow Time Limit: 5000/2000 MS (Java/Oth ...