一、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. UWP上可用的GB2312编码

    大概是在WP8的时候,网上有一个WP8可用的GB2312编码的解决方法,就是那个DBCSCodePage. 但是由于UAP开始,微软删掉了GetManifestResourceStream,所以这东西 ...

  2. LINUX 笔记-scp命令

    从本地服务器复制到远程服务器: (1) 复制文件: 命令格式: scp local_file remote_username@remote_ip:remote_folder (2) 复制目录: 命令格 ...

  3. 树莓派.GPRS.短信接收器

    起因 曾经用过西门子出的短信猫, 好处是直接有SDK开发包, 不会硬件开发也能直接使用 缺点也是明显的, 就是只支持Windows系统, 另外就是在Windows下工作很不稳定, 隔开几天就会出现收不 ...

  4. php mysqli MySQL server has gone away 问题分析

    结论 mysqli没有处理对端(MySQL server)的断开请求.在send时,收到对端(MySQL server)的RST,会打印MySQL server has gone away. 环境 x ...

  5. LeetCode 219. Contains Duplicate II (包含重复项之二)

    Given an array of integers and an integer k, find out whether there are two distinct indices i and j ...

  6. 微软Tech Summit 2017,等你来打Call

    2017年10月31至11月3日,由微软举办的Tech Summit 2017技术暨生态大会将在北京盛大举办,要在北京连开四天.今年的技术大会看头十足,不仅有大咖级人物带来十二大主题课程,更有三天四场 ...

  7. python学习笔记(十一)之函数

    牛刀小试: 定义一个无参函数 >>> def myFirstFunc(): ... print("Hello python") ... print("h ...

  8. HDU1222Wolf and Rabbit(GCD思维)

    Wolf and Rabbit Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)T ...

  9. 反馈法学习设计模式(一)——策略模式Strategy Pattern

    简介(Introduction) 之前学习Java8实战时,遇到一个很好的策略模式示例.便想着借着这个示例结合反馈式的方法来,学习策略设计模式,也以便后面反复琢磨学习. 首先我们通过练习,逐步写出符合 ...

  10. C# orderby子句

    注意:对联接运算的结果进行排序. 请注意,排序在联接之后执行. 虽然可以在联接之前将 orderby 子句用于一个或多个源序列,不过通常不建议这样做. 某些 LINQ 提供程序可能不会在联接之后保留该 ...