MVC中使用Hangfire执行定时任务
需求描述
项目中有一个通知公告的功能,在后台管理员添加公告后需要推送消息给所有注册用户,让其查看消息。消息推送移动端采用极光推送,但是消息在何时发送是个问题,比如说有一个重要的会议通知,可能希望在会议开始前半天进行提醒,仅仅使用后台代码处理起来可能比较麻烦,这时就需要考虑到使用作业来处理这种定时执行的业务。
在NET平台,作业有很多方式,可以diy一个系统作业,或者使用数据库的作业功能写一个定时执行,再有一种方案就是使用外部开源的定时任务系统来完成。
首先来说,采用系统DIY作业的方式。在不同平台上都有相应的命令来支持这一操作,完成起来也不是很难,但是这样的话应用程序会和系统高耦合,万一想换系统或者换服务器,作业内容直接丢失,再者如果搞不好维护起来也比较麻烦。所以这个pass掉了
再者说数据库,各大数据库也都支持作业功能,sql server 或者mysql等。同样面临的问题 第一,不同数据库命令不一致;第二,添加了作业以后在数据库调整,比如数据库服务迁移会导致作业中断;还有一点,数据库作业如果做定时数据更新,数据库备份是比较不错的选择,都在持久层层面,与业务无关。但是如果牵扯到业务,那就有些麻烦了,想象一下,数据库定时执行了一个邮件发送的任务,生成了一条邮件的记录,然后通知IIS相关进程发送邮件,很有些本末倒置的感觉。
前两者其实各有各的使用场景,还是那句话,技术没有好坏,只有适合不适合。针对我们的业务来说,发起于应用内,在应用内部解决是比较好的方案。这样就需要第三个方案,集成一个定时任务的系统进来(或者自己写一个,实话说真没写过不知道有大的工作量)。
NET平台定时任务
net平台开源的定时任务系统也有不少吧,比较知名的有Quartz.net、Hangfire等等。初次使用这些,选择的时候以满足业务的同时简单快速为主,综合看了一下,最后选择Hangfire。一下是摘自园子关于二者区别的部分 :
与quartz.net对比
在项目没有引入Hangfire之前,一直使用的是Quartz.net。个人认为Quartz.net在定时任务处理方面优势如下:
- 支持秒级单位的定时任务处理,但是Hangfire只能支持分钟及以上的定时任务处理
原因在于Hangfire用的是开源的NCrontab组件,跟linux上的crontab指令相似。
更加复杂的触发器,日历以及任务调度处理
可配置的定时任务
但是为什么要换Hangfire? 很大的原因在于项目需要一个后台可监控的应用,不用每次都要从服务器拉取日志查看,在没有ELK的时候相当不方便。Hangfire控制面板不仅提供监控,也可以手动的触发执行定时任务。如果在定时任务处理方面没有很高的要求,比如一定要5s定时执行,Hangfire值得拥有。抛开这些,Hangfire优势太明显了:
持久化保存任务、队列、统计信息
重试机制
多语言支持
支持任务取消
支持按指定
Job Queue
处理任务服务器端工作线程可控,即job执行并发数控制
分布式部署,支持高可用
良好的扩展性,如支持IOC、Hangfire Dashboard授权控制、Asp.net Core、持久化存储等
说了这么多的优点,我们可以有个案例,例如秒杀场景:用户下单->订单生成->扣减库存,Hangfire对于这种分布式的应用处理也是适用的,最后会给出实现。
想了解更多参见原文:Hangfire项目实践分享
在MVC中使用Hangfire
下文中开发环境为 Vs 2017,Net Framework 4.5+,数据库为sql server 2008 r2 (要求sql server 2008+)
- 首先在项目使用nuget引入相关包
项目上右键,管理Nuget程序包→浏览,输入Hangfire,分别安装Hangfire、Hangfire.core、Hangfire.Sqlserver;
在安装hangfire时会关联安装owin,如果不想引入Owin的话可以去掉,在注册服务的时候需要单独处理
- 右键当前项目,添加OWIN Startup类,在文件中编写代码
如下
- //指定使用Sqlserver进行定时任务的持久化
- GlobalConfiguration.Configuration.UseSqlServerStorage("DefaultConnection");
- //启用服务
- app.UseHangfireServer();
- //启用Dashboard面板
- app.UseHangfireDashboard();
- //指定使用Sqlserver进行定时任务的持久化
- 在项目中进入Controller文件夹,在HomeController中添加代码
- public ActionResult Index()
- {
- //支持基于队列的任务处理:任务执行不是同步的,而是放到一个持久化队列中,以便马上把请求控制权返回给调用者。
- var jobId = BackgroundJob.Enqueue(() => WriteLog("队列任务"));
- //延迟任务执行:不是马上调用方法,而是设定一个未来时间点再来执行。
- BackgroundJob.Schedule(() => WriteLog("延时任务"), TimeSpan.FromSeconds(10));
- //循环任务执行:一行代码添加重复执行的任务,其内置了常见的时间循环模式,也可基于CRON表达式来设定复杂的模式。
- RecurringJob.AddOrUpdate(() => WriteLog("每分钟执行任务"), Cron.Minutely); //注意最小单位是分钟
- //延续性任务执行:类似于.NET中的Task,可以在第一个任务执行完之后紧接着再次执行另外的任务
- BackgroundJob.ContinueWith(jobId, () => WriteLog("连续任务"));
- return View();
- }
WriteLog方法在控制台输出了一些当前的任务信息,实际业务中可以做很多事情,发邮件提醒、更新数据等等
- public void WriteLog(string msg)
- {
- Debug.WriteLine($"Hangfire于{DateTime.Now}执行了任务[{msg}]");
- }
- public ActionResult Index()
- F5运行程序,打开输出视图,看到如下内容
到此为止,Hangfire就已经可以使用了,我们打开数据库
可以看到数据库中增加了不少以HangFire起头的表,这些表就是Hangfire相关持久化生成的表。
回到浏览器,在当前浏览地址后输入/hangfire ,访问以下Hangfire的dashboard页面,看一下任务的执行情况
因为有一个间隔一分钟循环执行的任务,截图这么一会的功夫,就已经执行了11次。在这个页面中,可以把已经执行的任务再次执行,可以查看执行失败的任务。
参考:
HangFire任务调度实例(Console和MVC中)及Log4Net日志配置
MVC中使用Hangfire执行定时任务的更多相关文章
- AspNet MVC中使用Hangfire执行定时任务
Hangfire在Aspnet中执行定时任务: 第一步: NuGet中加入Hangfire包 第二步: 添加Owin的自启动 第三步.Hangfire的后台控制仪表盘默认情况下只能本地访问,外网访问需 ...
- SpringBoot中使用Scheduling执行定时任务
SpringBoot自带的 Schedule,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多 以下任务都是在单线程下执行的 第一步 创建SpringBoot项目 第二步 外汇 ...
- MVC中使用Hangfire按秒执行任务
更新Hangfire版本到1.7.0,才支持使用按秒循环任务执行 RecurringJob.AddOrUpdate("test",()=>writeLog("每20 ...
- MVC中Action的执行过程
接着上一篇:MVC控制器的激活过程 一.代码现行,该伪代码大致解析了Action的执行的过程 try { Run each IAuthorizationFilter's OnAuthorization ...
- Spring Mvc中使用Task实现定时任务,以及遇到的一个问题
Spring中实现定时任务其实很简单,可以使用spring中自带的task 相当于轻量级的Quartz,并且spring 3.0 之后支持注解的方式,使用起来非常简单,方便,具体实现如下: 第一步,修 ...
- mvc中使用Hangfire处理后台任务
考虑下如下代码,在数据保存后,需要发送邮件,发送邮件是个耗时的工作. 我们的目的是,数据保存成功后,就可以返回响应了,发送邮件不重要,不需要等待邮件发送成功 [HttpPost] public Act ...
- MVC中Action参数绑定的过程
一.题外话 上一篇:MVC中Action的执行过程 ControllerContext 封装有了与指定的 RouteBase 和 ControllerBase 实例匹配的 HTTP 请求的信息. 二. ...
- 白话学习MVC(八)Action的执行二
一.概述 上篇博文<白话学习MVC(七)Action的执行一>介绍了ASP.NET MVC中Action的执行的简要流程,并且对TempData的运行机制进行了详细的分析,本篇来分析上一篇 ...
- MVC中权限的知识点及具体实现代码
一:知识点部分 权限是做网页经常要涉及到的一个知识点,在使用MVC做权限设计时需要先了解以下知识: MVC中Url的执行是按照Controller->Action->View页面,但是我们 ...
随机推荐
- discuz回贴通知插件实现-显示用户状态设置
一.完善用户是否开启回贴通知 回贴通知插件建立模块时,指定了核心文件post_set.inc.php 1.创立好数据库 建立独立数据表(不建议直接修改原有的discuz数据库,防止discuz升级 ...
- geoserver笔记
geoserver中只支持shp 的数据的发布,也就是.shp的数据.其他的如mapgis的数据则需要转成.shp的格式 要发布地图数据为WMS服务,首先得建立工作空间(也可以使用现有的工作空间),然 ...
- 带你认识那些App可靠性设计
可靠性是软件一个重要的质量属性,它关注的是软件功能持续的可用性,以及出现故障之后是否能够容错,是否能快速的恢复使用. 可靠性六条基本准则 1.故障应在第一时间被检测和感知: 2.能避免的故障都不应该发 ...
- OSGi 系列(一)之什么是 OSGi :Java 语言的动态模块系统
OSGi 系列(一)之什么是 OSGi :Java 语言的动态模块系统 OSGi 的核心:模块化.动态.基于 OSGi 就可以模块化的开发 java 应用,模块化的部署 java 应用,还可以动态管理 ...
- 16款值得一用的iPhone线框图模板 (PSD & Sketch)
在任何网站或移动应用设计的过程中,线框图作为设计元素和功能的图示,它有助于帮助定义和更好地传达信息层次结构,让参与设计和开发的人员更好的理解设计师的思路和设计的功能点. 即使线框图设计是一个比较耗时的 ...
- 淘宝星星的思路c#
<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head><meta ...
- C#打印日志的小技巧
public static void Log(params System.Object[] message) { string str = ""; if (message == n ...
- shell中$(( ))、$( )与${ }的区别
转载自:http://blog.sina.com.cn/s/blog_4da051a60102uwda.html 命令替换 在bash中,$( )与` `(反引号)都是用来作命令替换的. 命令替换与变 ...
- modelsim仿真中Altera库的用法
添加altera 库 实例: 把建立lpm_mux IP时生成的.v文件lpm_mux_ip.v和编写的测试脚本文件放在一起,在modelsim中建立工程,把下面两个文件添加到工程中 直接compil ...
- 201709013工作日记--Android异步通信AsyncTask
参考相关博客:http://blog.csdn.net/liuhe688/article/details/6532519 在Android中实现异步任务机制有两种方式,Handler和AsyncTas ...