一、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的更多相关文章

  1. 后台工作者HangFire与ABP框架Abp.Hangfire及扩展

    HangFire与Quartz.NET相比主要是HangFire的内置提供集成化的控制台,方便后台查看及监控,对于大家来说,比较方便. HangFire是什么 Hangfire是一个开源框架(.NET ...

  2. ABP module-zero +AdminLTE+Bootstrap Table+jQuery权限管理系统第十四节--后台工作者HangFire与ABP框架Abp.Hangfire及扩展

    返回总目录:ABP+AdminLTE+Bootstrap Table权限管理系统一期 HangFire与Quartz.NET相比主要是HangFire的内置提供集成化的控制台,方便后台查看及监控,对于 ...

  3. [Abp 源码分析]十六、后台作业与后台工作者

    0. 简介 在某些时候我们可能会需要执行后台任务,或者是执行一些周期性的任务.比如说可能每隔 1 个小时要清除某个临时文件夹内的数据,可能用户会要针对某一个用户群来群发一组短信.前面这些就是典型的应用 ...

  4. ABP框架理论学习之后台工作(Jobs)和后台工作者(Workers)

    返回总目录 本篇目录 介绍 后台工作 后台工作者 让你的应用程序一直运行 介绍 ABP提供了后台工作和后台工作者,它们会在应用程序的后台线程中执行一些任务. 后台工作 后台工作以队列和持续的方式在后台 ...

  5. [Abp vNext 源码分析] - 12. 后台作业与后台工作者

    一.简要说明 文章信息: 基于的 ABP vNext 版本:1.0.0 创作日期:2019 年 10 月 24 日晚 更新日期:暂无 ABP vNext 提供了后台工作者和后台作业的支持,基本实现与原 ...

  6. ABP后台服务之作业调度Quartz.NET

    一.简介 Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中.它提供了巨大的灵活 ...

  7. ABP官方文档翻译 7.2 Hangfire集成

    Hangfire集成 介绍 ASP.NET Core集成 ASP.NET MVC 5.x集成 面板授权 介绍 Hangfire是一个综合的后台job管理器.你可以 把它集成到ABP,用来取代默认的后台 ...

  8. 实现ABP中Person类的权限功能

    菜单项的显示功能已经完全OK了.那么我们就开始制作视图功能吧. 首先测试接口是否正常 我们通过代码生成器将权限和application中大部分功能已经实现了.那么我们来测试下这些接口ok不. 浏览/a ...

  9. ECshop网点程序优化-后台添加类目自动选择上次父类目并计算Sort Order

    如果在ECshop后台批量添加过大量类目的人都能体会到是多么的不方便(这点还是要说一下ECshop的产品经理,细节上还是要多注意),每次添加都需要在几百个类目里面找到要添加的父类目也是一个麻烦事,比如 ...

随机推荐

  1. mysql主从复制的异步复制与同步复制

    异 步复制:MySQL本身支持单向的.异步的复制.异步复制意味着在把数据从一台机器拷贝到另一台机器时有一个延时 – 最重要的是这意味着当应用系统的事务提交已经确认时数据并不能在同一时刻拷贝/应用到从机 ...

  2. Linux入门(8)——Ubuntu16.04安装sublime text 3并配置Python开发环境

    打开终端,添加sublime text 3的仓库: 按enter键继续 更新软件库: sudo apt-get update 安装Sublime Text 3: sudo apt-get instal ...

  3. SPARK 学习笔记一

    1.Spark基于内存进行运算 2.Spark核心是SprintContext,是程序的入口 3.RDDs是提供抽象的数据集,通过RDDS可以方便对分布在各个节点的数据进行计算,而且忽略细节 4.RD ...

  4. NIO FileChannel

    NIO提供了比传统的文件访问更好的访问方法,NIO有两个优化的方法:一个是 FIleChannel.transferTo FileChannel.transferFrom,另一个是FileChanne ...

  5. java传值与传引用总结

    基本数据类型 我们先来看一个代码 public class ParamTest { public static void main(String[] arge) { double percent = ...

  6. Repeated Substring Pattern --重复字符串

    Given a non-empty string check if it can be constructed by taking a substring of it and appending mu ...

  7. SQL2008清空删除日志:

    SQL2008清空删除日志: '在SQL2008中清除日志就必须在简单模式下进行,等清除动作完毕再调回到完全模式. USE [master] GO ALTER DATABASE DNName SET ...

  8. 将本地web服务映射到公网访问

    本文始发于我的个人博客,如需转载请注明出处. 为了更好的阅读体验,可以直接进去我的个人博客看. 项目部署 之前在学习前端的时候项目都只是在本地测试,永远的都是类似 http://localhost/x ...

  9. 使用localstorage来存储页面信息

    今天小颖在跟着慕课网学习vue,不学不知道,一学吓一跳,学了才发现,我之前知道的只是vue的冰山一角,嘻嘻,今天把小颖跟着慕课网学习的demo,给大家分享下,希望对大家有所帮助嘻嘻. 环境搭建: 参考 ...

  10. python基础6 迭代器 生成器

    可迭代的:内部含有__iter__方法的数据类型叫可迭代的,也叫迭代对象实现了迭代协议的对象 运用dir()方法来测试一个数据类型是不是可迭代的的. 迭代器协议是指:对象需要提供next方法,它要么返 ...