Abp后台工作者类使用hangfire
一、Abp中的后台工作及后台工作者类
二 、Abp官方实现的缺点
Abp官方实现方式很简单,也很容易上手,但缺点是工作者类依赖了具体的基类(PeriodicBackgroundWorkerBase),就会存在应用程序耦合。

为什么会耦合呢,假设以后想采用HangFire或Quartz.NET来调度工作者,我们就需要把所有工作类的基类进行修改,这不利于系统的维护和可扩展,而且采用官方实现无法监测和管控工作者。
三、开始改造
1、核心库

要消除工作者类对具体调度类的依赖,则只能让后台工作者类继承自不含调度实现的基类(BackgroundWorkerBase)或直接实现接口(IBackgroundWorker)。我定义了一个泛型基类(BackgroundWorker<T>),该基类继承ABP核心库的BackgroundWorkerBase,同时该基类必须实现我自定定义的IBackgroundWorkerDo接口。
BackgroundWorker<T>:所有后台工作者类都该继承的基类,加泛型参数的目的是Hangfire的RecurringJob.AddOrUpdate<T>方法在创建轮询任务时必须知道它该调用哪个类的哪个方法
IBackgroundWorkerDo: 约束所有后台工作者类必须实现DoWork,配合泛型参数,Hangfire的轮询任务便可以知道T类型一定会有一个DoWork方法,然后在RecurringJob.AddOrUpdate<T>的方法体中便可以调用T类型实的DoWork方法
WorkerConfig类: 每个后台工作者都应该有一个唯一的标识,执行间隔时间,这样轮询代理类才知道如何处理
IBackgroudWorkerProxy: 代替后台工作者类执行其DoWork方法,所有轮询调度类都应该实现该接口
/// <summary>
/// 所有的后台工作者类都应实现该接口
/// </summary>
public interface IBackgroundWorkerDo
{
/// <summary>
/// 执行具体的任务
/// </summary>
void DoWork();
}
/// <summary>
/// 所有后台工作者类都应继承该类
/// </summary>
public abstract class BackgroundWorker<T> : BackgroundWorkerBase, IBackgroundWorkerDo where T : IBackgroundWorkerDo
{
protected readonly IBackgroudWorkerProxy _workProxy;
protected readonly WorkerConfig _config;
protected BackgroundWorker(IBackgroudWorkerProxy workProxy, WorkerConfig config)
{
_workProxy = workProxy;
_config = config;
}
/// <summary>
/// 任务启动
/// </summary>
public override void Start()
{
Logger.Debug("轮询任务启动");
_workProxy.Excete<T>(DoWork, _config); //主要指定当前任务类,不然hangfire无法调用,不然可以移到父类去
}
/// <summary>
/// 具体的任务执行
/// </summary>
public abstract void DoWork();
}
/// <summary>
/// 工作任务配置
/// </summary>
public class WorkerConfig
{
/// <summary>
/// 轮询秒数
/// </summary>
public int IntervalSecond { get; set; }
/// <summary>
/// 工作唯一编号
/// </summary>
public string WorkerId { get; set; }
}
public interface IBackgroudWorkerProxy
{
/// <summary>
/// 执行
/// </summary>
/// <param name="method"></param>
void Excete<T>(Action method, WorkerConfig config) where T : IBackgroundWorkerDo;
}
以上便是解耦的核心代码,在核心代码中,仿照Abp官方的PeriodicBackgroundWorkerBase类提供了一个基于Timer的轮询调度实现:
public class PeriodicWorkerPxoxy : IBackgroudWorkerProxy
{
private Action ExetuteMethod { get; set; }
protected readonly AbpTimer Timer;
public PeriodicWorkerPxoxy(AbpTimer timer)
{
Timer = timer;
Timer.Elapsed += Timer_Elapsed;
} private void Timer_Elapsed(object sender, EventArgs e)
{
try
{
DoWork();
}
catch (Exception ex)
{ }
} public void Excete<T>(Action method, WorkerConfig config) where T: IBackgroundWorkerDo
{
ExetuteMethod = method;
Timer.Period = config.IntervalSecond*;//将传入的秒数转化为毫秒
Timer.Start();
} protected void DoWork()
{
ExetuteMethod();
}
}
作为一个核心模块,所以还需要定义一个模块启动配置文件
public class FastWorkWorkerPxoxyModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
public override void PreInitialize()
{
IocManager.RegisterIfNot<IBackgroudWorkerProxy, PeriodicWorkerPxoxy>();
}
}
核心库解决方案图如下,(记住要引用Abp核心库)

在需要的项目中引入该Dll,然后按照模块启动配置依赖进行配置
[DependsOn(typeof(AbpZeroCoreModule), typeof(AbpZeroLdapModule), typeof(AbpAutoMapperModule), typeof(FastWorkWorkerPxoxyModule))]
public class FastWorkCoreModule : AbpModule
{
...
}
后台工作者类示例:
namespace ORS.FastWork.Core.Sms
{
/// <summary>
/// 清理短信日志
/// </summary>
public class SmsWorker : BackgroundWorker<SmsWorker>, ISingletonDependency
{
private readonly IRepository<SmsSendLog, long> _smsLogRepository;
public SmsWorker(IRepository<SmsSendLog, long> smsLogRepository,IBackgroudWorkerProxy workMiddleware) : base(workMiddleware, new WorkerConfig { IntervalSecond=,WorkerId="smsworker"})
{
_smsLogRepository = smsLogRepository;
}
public override void DoWork()
{
//_smsLogRepository.Insert(new SmsSendLog { IsOk = true, Content = "轮询任务创建的", CreationTime = DateTime.Now });
}
}
}
2、HangFire实现
主要的类有两个,一个是启动配置,一个实现了IBackgroudWorkerProxy接口,解决方案目录如下:

解决方案记得引用上面定义好的核心库,Hangfire实现轮询的代码如下:
public class HangfireWorkerPxoxy : IBackgroudWorkerProxy
{
public HangfireWorkerPxoxy()
{ }
private WorkerConfig Config { get; set; }
public void Excete<T>(Action method, WorkerConfig config) where T: IBackgroundWorkerDo
{
Config = config;
string workerId = config.WorkerId;
string cron = Cron.MinuteInterval(config.IntervalSecond/);
RecurringJob.AddOrUpdate<T>(config.WorkerId, (t)=>t.DoWork(), cron,TimeZoneInfo.Local);
RecurringJob.Trigger(config.WorkerId);
}
}
模块启动文件中的代码很关键,当后台工作采用了Hangfire来调度时(即在web模块的启动文件中使用了 Configuration.BackgroundJobs.UseHangfire(...)),则后台工作者类的调度也将由我们核心库中的PeriodicWorkerPxoxy变更为Hangfire来接管
public class HangFireWorkerModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
public override void PreInitialize()
{
IocManager.RegisterIfNot<IBackgroudWorkerProxy, HangfireWorkerPxoxy>();
}
public override void PostInitialize()
{
//判断是否启用了hangfire,如果启用了,则将IBackgroudWorkerProxy的实例改为hangfire
var hangfireConfig = IocManager.Resolve<IAbpHangfireConfiguration>();
if (hangfireConfig?.Server!= null) {
IocManager.IocContainer.Register(Component.For<IBackgroudWorkerProxy>().ImplementedBy<HangfireWorkerPxoxy>().IsDefault());
}
}
}
在Web项目中引用该项目,然后在模块启动中加入对该模块的依赖

在PostInitialize方法中向后台工作管理类加入具体的工作

最终效果如下:


3.进一步优化
该方案目前已在我们公司的项目中投入使用,由于时间和精力关系,我个人没有对该方案进行进一步优化。在web模块启动文件中,还是需要做两步工作:1.引用了dll 2.启动文件上标注依赖关系,每增加一种轮询调度方式我们都需要重复这两步,如果想做得更灵活的话,可以弄成插件模块(拷入dll到站点PlugIns目录,然后再后台设置一下即可),下一篇文章我会以短信网关插件实战来演示Abp插件模块的妙用。
Abp后台工作者类使用hangfire的更多相关文章
- 后台工作者HangFire与ABP框架Abp.Hangfire及扩展
HangFire与Quartz.NET相比主要是HangFire的内置提供集成化的控制台,方便后台查看及监控,对于大家来说,比较方便. HangFire是什么 Hangfire是一个开源框架(.NET ...
- ABP module-zero +AdminLTE+Bootstrap Table+jQuery权限管理系统第十四节--后台工作者HangFire与ABP框架Abp.Hangfire及扩展
返回总目录:ABP+AdminLTE+Bootstrap Table权限管理系统一期 HangFire与Quartz.NET相比主要是HangFire的内置提供集成化的控制台,方便后台查看及监控,对于 ...
- [Abp 源码分析]十六、后台作业与后台工作者
0. 简介 在某些时候我们可能会需要执行后台任务,或者是执行一些周期性的任务.比如说可能每隔 1 个小时要清除某个临时文件夹内的数据,可能用户会要针对某一个用户群来群发一组短信.前面这些就是典型的应用 ...
- ABP框架理论学习之后台工作(Jobs)和后台工作者(Workers)
返回总目录 本篇目录 介绍 后台工作 后台工作者 让你的应用程序一直运行 介绍 ABP提供了后台工作和后台工作者,它们会在应用程序的后台线程中执行一些任务. 后台工作 后台工作以队列和持续的方式在后台 ...
- [Abp vNext 源码分析] - 12. 后台作业与后台工作者
一.简要说明 文章信息: 基于的 ABP vNext 版本:1.0.0 创作日期:2019 年 10 月 24 日晚 更新日期:暂无 ABP vNext 提供了后台工作者和后台作业的支持,基本实现与原 ...
- ABP后台服务之作业调度Quartz.NET
一.简介 Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中.它提供了巨大的灵活 ...
- ABP官方文档翻译 7.2 Hangfire集成
Hangfire集成 介绍 ASP.NET Core集成 ASP.NET MVC 5.x集成 面板授权 介绍 Hangfire是一个综合的后台job管理器.你可以 把它集成到ABP,用来取代默认的后台 ...
- 实现ABP中Person类的权限功能
菜单项的显示功能已经完全OK了.那么我们就开始制作视图功能吧. 首先测试接口是否正常 我们通过代码生成器将权限和application中大部分功能已经实现了.那么我们来测试下这些接口ok不. 浏览/a ...
- ECshop网点程序优化-后台添加类目自动选择上次父类目并计算Sort Order
如果在ECshop后台批量添加过大量类目的人都能体会到是多么的不方便(这点还是要说一下ECshop的产品经理,细节上还是要多注意),每次添加都需要在几百个类目里面找到要添加的父类目也是一个麻烦事,比如 ...
随机推荐
- 张高兴的 Windows 10 IoT 开发笔记:使用 ULN2003A 控制步进电机
GitHub:https://github.com/ZhangGaoxing/windows-iot-demo/tree/master/ULN2003A
- LINUX 笔记-read命令
作用:读入值给变量 1.read 从键盘读入字符到name变量 2.read -p 'msg' var... 输入提示 3.read -s vars 隐藏输入 4.read读取文件时,每次调用会读取 ...
- 典型的NIO代码
public void selector() throws IOException { ByteBuffer buffer = ByteBuffer.allocate(1024); Selector ...
- iOS 通讯录空格
iOS 通讯录联系人出现 ASCII 码值为 160 的空格 NOTE: 这里的"空格"是指 在通讯录中取出的联系人中带有特殊空格 带有特殊空格的字符串 " ...
- C#基本功之泛型
一.没有泛型之前 在没有泛型之前,我们是怎么处理不同类型的相同操作的: 示例1 //下面是一个处理string类型的集合类型 public class MyStringList { string[] ...
- Memcached存储命令
Memcached各个存储命令的语法格式都类似,且有相同的参数和参数含义,先将可能出现的各个参数的意义说明如下: key: 键值 key-value 结构中的 key,用于查找缓存值. flag ...
- LeetCode 56. Merge Intervals (合并区间)
Given a collection of intervals, merge all overlapping intervals. For example,Given [1,3],[2,6],[8,1 ...
- 版本12.2.0.1.0数据库,复制种子数据库快速创建租户数据库PDB
实验测试:快速创建一个数据库PDB2: 实验环境:12.2.0.1.0版本数据库,dbca图形化安装,现有环境,CDB容器数据库ORCL,PDB可插拔数据库ABC ---查询CDB名称,状态 SQ ...
- Unity3D手机斗地主游戏开发实战(02)_叫地主功能实现(不定期更新中~~~)
目录 Unity3D手机斗地主游戏开发实战(01)_发牌功能实现 Unity3D手机斗地主游戏开发实战(02)_叫地主功能实现 一.大体思路 前面我们实现了点击开始游戏按钮,系统依次给玩家发牌的逻辑和 ...
- Java中方法的重载和重置(覆盖)的区别
简单来说,重载就是在同一类中允许同时存在一个以上的同名方法,只要这些方法的参数个数或类型不同即可,而重置(覆盖)是子类重新定义父类中己经定义的方法,即子类重写父类方法. 方法的重载 方法的重载就是在同 ...