本系列目录:Abp介绍和经验分享-目录

什么是后台作业系统

后台作业系统即BackgroundJob,从需求上讲,是一套基础设施,允许我们定义一个作业,在未来指定的某个时间去执行。

后台作业的一般场景:

  1. 如果某个业务逻辑很复杂,但又不是立即需要反馈结果给用户;
  2. 如果有个任务需要定时循环执行;
  3. 如果有个批量任务;
  4. 如果有个任务需要延后一段时间(在未来某个指定的时间)执行;

举几个典型例子:

  1. 订单在创建后30分钟未支付则自动取消并释放库存;
  2. 一个有几万甚至几十万粉丝的公众号需要同步粉丝信息到数据库;
  3. 某个活动开始前15分钟通知感兴趣的用户进行预热;
  4. 某个与友商合作的项目涉及结算,需要在每月指定日子出账单;
  5. 每天空闲时间段全量刷新缓存或者重建索引;

Abp的后台作业系统

Abp的后台作业系统有两个抽象概念:

  1. BackgroundWorker;
  2. BackgroundJob;

如果是第一次用Abp的后台作业系统,可以点击下面这个链接到官方文档看具体使用方法,这里主要介绍下这两个的特点和联系。

Background Jobs and Workers

BackgroundWorker

先说BackgroundWorker,BackgroundWorker其实就是基于一个TimerAbpTimer)设置时间间隔,在进程中定时执行。

在Abp核心模块AbpKernelModulePostInitialize方法的最后:

if (Configuration.BackgroundJobs.IsJobExecutionEnabled)
{
var workerManager = IocManager.Resolve<IBackgroundWorkerManager>();
workerManager.Start();
workerManager.Add(IocManager.Resolve<IBackgroundJobManager>());
}

我们看到可以通过Configuration.BackgroundJobs.IsJobExecutionEnabled控制是否启用workerManager,同时IBackgroundJobManager其实是个Worker(这里说的是JobManager,不是Job)。

BackgroundJob

IBackgroundJobManager继承了IBackgroundWorker,并且Abp默认实现的BackgroundJobManager也是基于Worker的机制,其基类是PeriodicBackgroundWorkerBase,静态构造方法中指定了每5秒拉取一次作业信息。

Abp.dll程序集中,Configuration.BackgroundJobs.IsJobExecutionEnabled启用时,默认用InMemoryBackgroundJobStore来存储作业信息。

在Abp核心模块AbpKernelModulePostInitialize方法的最开始RegisterMissingComponents(假如没有注册其他实现):

if (Configuration.BackgroundJobs.IsJobExecutionEnabled)
{
IocManager.RegisterIfNot<IBackgroundJobStore, InMemoryBackgroundJobStore>(DependencyLifeStyle.Singleton);
}
else
{
IocManager.RegisterIfNot<IBackgroundJobStore, NullBackgroundJobStore>(DependencyLifeStyle.Singleton);
}

如果Configuration.BackgroundJobs.IsJobExecutionEnabled未启用,则用NullBackgroundJobStore,如果启用,默认用的是InMemoryBackgroundJobStore,除非仅作演示用,否则InMemoryBackgroundJobStore没什么用,因为这些默认实现都没处理集群场景下Job的分布式执行和防止重复执行。

为便于我们在生产环境使用,看下面两个:

Abp框架提供了Abp.HangfireAbp.Quartz模块用于集成可用于集群化场景下的作业实现(防止重复执行等问题,Abp默认实现的IBackgroundWorkerManagerIBackgroundJobManager并未处理相关问题);

总结下

上面有点缺乏条理,总结下:

  1. Configuration.BackgroundJobs.IsJobExecutionEnabled不仅影响BackgroundJob的执行,同时也影响BackgroundWorker的执行;
  2. Abp默认实现的IBackgroundJobStore不支持集群环境下、分布式环境下的Job执行;
  3. Abp框架提供了Abp.HangfireAbp.Quartz模块支持集群环境下、分布式环境下的Job执行;

然后,还有个关于module-zero的小坑,提一下:

当我们项目中使用了module-zero模块,这个模块在业务数据库中实现了一个简单版本的IBackgroundJobStore

对,还是没处理重复执行的问题,而且你不用配置,只要用了module-zero,但没配置用Hangfire或者Quartz,这个机制就悄无声息的在跑!

这时候,job可能会重复执行,job可能去不同项目执行。

好多朋友都被这个坑过,引起的现象能让你怀疑人生!

module-zero的这个实现,个人认为是abp演示Notification机制的需要,其中有个分发机制是超出5人订阅,则转为Job进行分发。

明确一下不同Job配置实际上用的是哪个IBackgroundJobStore

  1. 什么都不配置,而且没依赖module-zero模块:IsJobExecutionEnabled默认是启用的,用的是基于内存的InMemoryBackgroundJobStore

  2. 什么都不配置,而且依赖了module-zero模块:用的是基于业务数据库的BackgroundJobStore,实体是BackgroundJobInfo,并且注册在AbpZeroDbContext中;

  3. 明确关闭IsJobExecutionEnabled:如果没依赖module-zero则用的是空实现NullBackgroundJobStore,不进行存储,否则作业信息可以入队,能在其他开启job执行的宿主项目上执行(假如共享了job代码所在的程序集);

  4. 明确配置依赖了Abp.HangfireAbp.QuartzIsJobExecutionEnabled启用的项目会执行,IsJobExecutionEnabled关闭的项目只入队不执行。

我们推荐的做法是(前提是核心的几个程序集共享,Abp框架并不是只能用于Web开发,也可以寄宿在控制台或win服务中,甚至桌面应用程序),所有iis站点关闭Job的执行,专门提供一个Windows服务启用IsJobExecutionEnabled

所有宿主程序都必须明确配置集成Abp.HangfireAbp.Quartz,哪怕你觉得这个项目和作业系统八竿子打不着!

所有宿主程序都必须明确配置集成Abp.HangfireAbp.Quartz,哪怕你觉得这个项目和作业系统八竿子打不着!

所有宿主程序都必须明确配置集成Abp.HangfireAbp.Quartz,哪怕你觉得这个项目和作业系统八竿子打不着!

我中招的那次,有怀疑过是不是AppDomain串了,甚至怀疑代码去不同进程串门了,怀疑人生。

最后差点忘说了,如果集成且启用了Hangfire,一定记得单独给他配个数据库,作业信息的扫描频率实在太高,据说Hangfire收费版支持存Redis,估计会好一点。

[2017-09-05]Abp系列——Abp后台作业系统介绍与经验分享的更多相关文章

  1. [2017-08-21]Abp系列——如何使用Abp插件机制(注册权限、菜单、路由)

    本系列目录:Abp介绍和经验分享-目录 Abp的模块系统支持插件机制,可以在指定目录中放置模块程序集,然后应用程序启动时会搜索该目录,加载其中所有程序集中的模块. 如何使用这套机制进行功能插件化开发? ...

  2. 基于DDD的现代ASP.NET开发框架--ABP系列文章总目录

    ABP相关岗位招聘:给热爱.NET新技术和ABP框架的朋友带来一个高薪的工作机会 ABP交流会录像视频:ABP架构设计交流群-7月18日上海线下交流会的内容分享(有高清录像视频的链接) 代码自动生成: ...

  3. ABP文档 - 后台作业和工作者

    文档目录 本节内容: 简介 后台作业 关于作业持久化 创建一个后台作业 在队列里添加一个新作业 默认的后台作业管理器 后台作业存储 配置 禁用作业执行 Hangfire 集成 后台工作者 创建一个后台 ...

  4. 基于DDD的现代ASP.NET开发框架--ABP系列之3、ABP分层架构

    基于DDD的现代ASP.NET开发框架--ABP系列之3.ABP分层架构 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ABP的官方网站:ht ...

  5. 基于DDD的现代ASP.NET开发框架--ABP系列之2、ABP入门教程

    基于DDD的现代ASP.NET开发框架--ABP系列之2.ABP入门教程 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boi ...

  6. 点这里进入ABP系列文章总目录

    基于DDD的现代ASP.NET开发框架--ABP系列之1.ABP总体介绍 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boi ...

  7. [2017-09-04]Abp系列——为什么值对象必须设计成不可变的

    本系列目录:Abp介绍和经验分享-目录 这篇是之前翻备忘录发现漏了的,前阵子刚好同事又提及过这个问题,这里补上. 本文重点在于理解什么是值对象的不可变性. Abp的ValueObject以及EF的Co ...

  8. [2017-08-28]Abp系列——业务异常与错误码设计及提示语的本地化

    本系列目录:Abp介绍和经验分享-目录 前言 ABP中有个异常UserFriendlyException经常被使用,但是它所在的命名空间是Abp.UI,总觉得和展现层联系过于紧密,在AppServic ...

  9. [2017-08-16]ABP系列——QuickStartB:正确理解Abp解决方案的代码组织方式、分层和命名空间

    本系列目录:Abp介绍和经验分享-目录 介绍ABP的文章,大多会提到ABP框架吸收了很多最佳实践,比如: 1.N层 (复用一下上篇的图) 展现层(Personball.Demo.Web):asp.ne ...

随机推荐

  1. MySQL的一个麻烦事

    1. 开启一个MySQL连接,在这个连接中发起一个事务,进行一些操作但不提交 2. 拔网线 3. 重连网线,再开启一个MySQL连接,执行delete操作,发现stpe 1中占用的资源没有被释放 4. ...

  2. android 扩大view的响应区域

    1.Android提供TouchDelegate帮助实现扩大一个很小的view的点击区域 例如:https://developer.android.com/training/gestures/view ...

  3. Extjs grid 单元格事件

    celldblclick: function (view, td, cellIndex, record, tr, rowIndex, e, eOpts) { //extjs 4.2下,有时出现,多次不 ...

  4. php 打印今天,昨天,本周,上周,当月,上月,本季,上季,今年,去年数据

    if($filter['mode']) { switch ($filter['mode']) { case 1://今天的数据 $time_start = date("Y-m-d H:i:s ...

  5. atom 隐藏右边的白线

    atom-text-editor.editor .wrap-guide {//隐藏右边的白线visibility: hidden;}

  6. PopupMenu和对话框的使用

    PopupMenu和对话框的使用 1.菜单的使用之 PopupMenu 步骤:1.创建popupMenu对象 参数:上下文对象   当前view对象 2.利用getMenu().addSubMenu创 ...

  7. vim 树形菜单插件NERDTree 的安装

    vim 树形菜单插件的安装 NERDTree 1. mkdir ~/.vim cd ~/.vim mkdir bundle mkdir autoload 2.  curl -Sso ~/.vim/au ...

  8. windows下配置redis集群,启动节点报错:createing server TCP listening socket *:7000:listen:Unknown error

    windows下配置redis集群,启动节点报错:createing server TCP listening socket *:7000:listen:Unknown error 学习了:https ...

  9. selector在手机上或浏览器显示各种姿势(虚拟下拉菜单)

    测试机型:小米.华为.苹果 测试浏览器:Chrome.Safari.Firefox 最后的结果就是你搞你的,我搞我的! 我认为这样漂亮,你认为那样漂亮(我认为你们都统一!) 因为项目时间紧,所以直接用 ...

  10. 指针初始化为NULL的作用

    关于空指针NULL.野指针.通用指针,首先说一下什么是指针,只要明白了指针的含义,你就明白null的含义了. 假设 有语句 int a=10;那么编译器就在内存中开辟1个整型单元存放变量a,我们假设这 ...