HangFire快速入门 分布式后端作业调度框架服务

安装

NuGet 上有几个可用的Hangfire 的软件包。如果在ASP.NET应用程序中安装HangFire,并使用Sql Server作为存储器,那么请在Package Manager Console窗口中键入以下命令:

PM> Install-Package Hangfire

配置

在安装package后,添加或者更新以下几行到Owin Startp类:

复制代码
using Hangfire;

// ...

public void Configuration(IAppBuilder app)
{
    GlobalConfiguration.Configuration.UseSqlServerStorage("<connection string or its name>");

    app.UseHangfireDashboard();
    app.UseHangfireServer();
}
复制代码

需要配置授权

默认情况下,只有本地有权限访问Hangfire仪表板。如果需要授权远程访问,那么仪表板的授权必须进行相应的配置。

然后打开Hangfire仪表板来测试您的配置。编译项目并在浏览器中打开以下URL:

1
http: //<your-site>/hangfire

用法

添加工作

HangFire处理不同类型的后台任务,并且使用一个独立的上下文环境调用他们。

Fire-And-forget(发布/订阅)

这是一个主要的后台任务类型,持久化消息队列会去处理这个任务。当你创建了一个发布/订阅任务,该任务会被保存到默认队列里面(默认队列是"Default",但是支持使用多队列)。多个专注的工作者(Worker)会监听这个队列,并且从中获取任务并且完成任务。

BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget"));

延迟

如果想要延迟某些任务的执行,可以是用以下任务。在给定延迟时间后,任务会被排入队列,并且和发布/订阅任务一样执行。

BackgroundJob.Schedule(() => Console.WriteLine("Delayed"), TimeSpan.FromDays(1));

循环

按照周期性(小时,天等)来调用方法,请使用RecurringJob类。在复杂的场景,您可以使用CRON表达式指定计划时间来处理任务。

RecurringJob.AddOrUpdate(() => Console.WriteLine("Daily Job"), Cron.Daily);

连续

连续性允许您通过将多个后台任务链接在一起来定义复杂的工作流。

var id = BackgroundJob.Enqueue(() => Console.WriteLine("Hello, "));
BackgroundJob.ContinueWith(id, () => Console.WriteLine("world!"));

释放

Hangfire将您的任务保存到持久化库汇总,并且以可靠的方式处理它们。这意味着,你可以中断Hangfire Worder的线程,重新加载应用程序域,或者终止程序,即使这样您的任务仍会被处理。只有在你代码的最后一行执行完成,Hangfire才会标记这个任务完成。并且知道任务可能在最后一行代码执行之前失败。它包含多种 自动-重试机制,它可以自动处理在存储或代码执行过程中发生的错误。

这对于通用托管环境(如IIS Server)非常重要。它们可以包含不同的优化,超时和错误处理代码(可能导致进程终止)来防止不好的事情发生。如果您没有使用可靠的处理和自动机制,您的工作可能会丢失。您的最终用户可能无限期等待某些任务,如电子邮件,报告,通知等。

但是当您的存储空间破损时,Hangfire无法做任何事情。请为您的存储使用不同的故障切换策略,以保证在发生灾难时处理每个作业。

原文地址:http://docs.hangfire.io/en/latest/quick-start.html

HangFire简述:
分布式后端作业调度框架服务,我们只需要关心业务逻辑代码,而不用关心调度机制,支持.net framework和.net core

HangFire基本结构:
客户端(创建任务)、服务端(执行任务)、数据库(存储任务列表和执行状况)、仪表盘(在网站上对任务进行监控查看和各种操作)

HangFire适用场景:
定时执行任务、循环执行任务、异步执行耗时任务、A任务执行完成再执行B任务、批量执行任务

HangFire官网: https://www.hangfire.io/
HangFire中文文档:http://koukouge-hangfire.daoapp.io/quick-start.html 
HangFire英文文档:http://docs.hangfire.io/en/latest/quick-start.html 
HangFire源码地址: https://github.com/HangfireIO


image

实战经验分享:
网上资料不是很多 都是按照官方例子在讲解,缺少很多关键性的概念讲解,导致很多伙计在实战中遇到各种坑。

1、客户端:创建任务-->1、配置HangFire数据库连接 2、创建任务(在创建任务的时候HangFire会自动将任务序列化并存储到数据)

2、服务端:执行任务-->1、配置HangFire数据库连接 2、从HangFire数据库系统表读取客户端创建的任务然后开线程并行执行,任务之间不冲突。(服务端可宿主在Windows服务、控制台程序、IIS中…)

3、数据库:HangFire程序框架表-->创建任务的时候HangFire会自动生成无需关心,但要注意如果采用现有的数据库,必须保证数据库中没有重名的表,否则你懂(aggregatedcounter、counter、distributedlock、hash、job、jobparameter、jobqueue、jobstate、list、server、set、state),数据库可采用 MySQL ,MSSQL,Redis视需要而定

4、仪表盘:展示作业列表执行状态和结果等相关信息-->在.Net WebForm或.Net MVC 或.NetCore MVC网站程序对接HangFire数据库,MVC 对接方式和WebForm略微不同 请参考官方文档


如何正确理解架设部署上述4个板块:
重点说客户端、服务端、仪表盘直之间的关系,数据库就不用多说了

方案1(不推荐):客户端A、服务端B、仪表盘C 分别运行在3个独立的项目中
优缺点:没什么优点,而且AB分开会导致服务端B从数据库提取任务列表,准备反向加载程序集执行任务的时候,在自己的程序代码中找不到对应的业务逻辑代码或者引用类,因为业务逻辑代码是在客户端A项目中创建,自然业务逻辑类及功能代码都在A项目的程序集中,自然找不到。

例子:客户端A创建的作业是引用YourOwnJobLibrary.dll类中 ShowMeTheMoney() 方法,而服务端B中没有引用YourOwnJobLibrary.dll 所以无法执行任务ShowMeTheMoney(),

报错:System.IO.FileNotFoundException
Could not load file or assembly 'DotNetFrameWorkConsoleApplicationHangFire, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. ???????????
System.IO.FileNotFoundException: Could not load file or assembly 'DotNetFrameWorkConsoleApplicationHangFire, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. ???????????
File name: 'DotNetFrameWorkConsoleApplicationHangFire, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMarkHandle stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName, ObjectHandleOnStack type, ObjectHandleOnStack keepalive)
at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName)
at System.RuntimeType.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark)
at System.Type.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase)
at Hangfire.Storage.InvocationData.Deserialize()

解决方案:让服务端B也引用YourOwnJobLibrary.dll即可,但是这并不是我们想要的结果,以后更新服务什么的还得两头更新很麻烦。

方案2(推荐):客户端A、服务端B在同一个项目中,仪表盘C独立网站项目中
优缺点:这样比较合理,更新服务方便,即便没有仪表盘C,作业正常调度执行;适合后台相对固定的作业。
可以将AB放在Windows服务项目中(VS中可以创建),这样系统重启什么的毫无顾虑,更新服务程序的时候只需停止服务->替换程序->开启服务即可。

方案3(还行):客户端A、服务端B、仪表盘C在同一网站项目只能是网站项目,因为仪表盘只能在Web项目(API、WebForm、MVC )中
优缺点:视情况也未尝不可,如果宿主在IIS中,IIS默认20分钟没有人访问会停止,HangFire作业服务也会定制,可将此时间在IIS配置中延长,比较适合任务经常需要灵活变动处理的场景。

重要信息备注:
注1:创建任务可以是在控制台程序Main方法中执行一次把任务Load到数据库,或则在网站上用户点击某个按钮执行后端方法创建。


注2:服务端比较灵活,可宿主在Windows服务、控制台程序、IIS中…

注3:首次启动连接数据库时,会自动生成12张系统表,请确保现有库中不存在以下表名:aggregatedcounter、counter、distributedlock、hash、job、jobparameter、jobqueue、jobstate、list、server、set、state


注4:原则上同一台电脑上只需要1个服务端存在,测试中发现这么一种情况:服务端B宿主在D控制台程序中,因误操作在仪表盘C网站项目中也启动一个HangeFire宿主服务E,最后的结果是服务端B的程序失效,服务端E正常运作,但是仪表盘上显示找不到任务作业对应的程序集,因为程序集在服务端B程序中,如方案1的System.IO.FileNotFoundException…


注5:HangFire执行的任务里面如果涉及到C盘创建文件夹 可能会因为权限问题 创建失败,采用管理员权限运行程序即可创建


实例:按照方案2思路测试

  1. 创建一个.net core 2.0控制台项目(.net framework/.net core2.0都行)
  2. 安装nuget Hangfire(针对控制台程序可以只安装Hangfire.core即可 )
  3. 安装nuget HangFire.MySql.Core(.net framework 也引用此包 如果用HangFire.MySql 下面的配置数据库链接事变)
  4. 安装好后就可以在Main方法中使用了

image

注:控制台程序关闭,也就是HangFire宿主程序停止,作业无法继续执行,想检测服务作业是否在执行,可定时往记事本中写入当前时间。

5、网站(.net core)中配置HangFire仪表盘:( .net framework 的网站配置不一样 尚未测试)
image

注1:app.UseHangfireDashboard(); 是让网站仅仅可以访问HangFire数据库的作业详情,不负责业务代码的执行。

注2:app.UseHangfireServer();是让HangFire服务宿主在Web程序中,参加上面方案2和方案3,如果是方案2则不应该添加此语句,方案3则添加此语句。


运行项目访问HangFire仪表盘: http://localhost:56013/hangfire/
image

image

猜你喜欢

转载自www.cnblogs.com/webenh/p/10641092.html