技术 思绪 摘录 旅行
Hangfire是一个任务调度的组件,自带面板,可以操作正在运作的任务,可以看到执行情况,而且使用起来简单,Hangfire不受特定.NET应用程序类型的限制,只要是.NET Framework 4.5以上,Newtonsoft.Json library ≥ 5.0.1,有一个mysql或者mssql数据库即可。而且最新的支持.NET Core,这篇文章主要记录一下如何在.NET Core 3.1中用mysql来帮助Hangfire实现持久化。

另一篇介绍任务调度的文章:.net平台下利用Quartz实现高可用的任务调度

首先官网推荐的是利用SQLSERVER来实现持久化,本文主要记录使用MySql实现持久化,想了解mssql操作的,请看官方中文文档:Hangfire中文文档


首先我们创建一个.NET Core 3.1的Web空项目。

image.png

我们需要引用三个DLL,Hangfire官网包,一个是第三方扩展的MySql扩展包

image.png

修改配置文件,把mysql连接字符串配置好

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "MySqlServerConStr": "server=127.0.0.1;User ID=root;Password=123456;database=hangfire;charset=utf8mb4;Allow User Variables=true;"
}

修改Startup.cs

首先添加注入,把配置项注入一下

        private readonly IConfiguration _configuration;
        /// <summary>
        ///配置注入
        /// </summary>
        /// <param name="configuration">The configuration.</param>
        public Startup(IConfiguration configuration)
        {
            _configuration = configuration;
        }

修改ConfigureServices方法

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddHangfire(x => x.UseStorage(new MySqlStorage(_configuration["MySqlServerConStr"],
                new MySqlStorageOptions
                {
                    TransactionIsolationLevel = IsolationLevel.ReadCommitted, // 事务隔离级别。默认是读取已提交。
                    QueuePollInterval = TimeSpan.FromSeconds(15),             //- 作业队列轮询间隔。默认值为15秒。
                    JobExpirationCheckInterval = TimeSpan.FromHours(1),       //- 作业到期检查间隔(管理过期记录)。默认值为1小时。
                    CountersAggregateInterval = TimeSpan.FromMinutes(5),      //- 聚合计数器的间隔。默认为5分钟。
                    PrepareSchemaIfNecessary = true,                          //- 如果设置为true,则创建数据库表。默认是true。
                    DashboardJobListLimit = 50000,                            //- 仪表板作业列表限制。默认值为50000。
                    TransactionTimeout = TimeSpan.FromMinutes(1),             //- 交易超时。默认为1分钟。
                    TablesPrefix = "Hangfire"                                  //- 数据库中表的前缀。默认为none
                }
                )));
        }

将服务加入到管道中,修改Configure方法

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHangfireServer();      //启动hangfire服务
            app.UseHangfireDashboard();   //使用hangfire面板

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });
        }

这时候,本地的面板已经可以打开的,我们运行不调试:localhost:5050/hangfire

image.png

这时候我们去看我们的数据库,会发现自动生成了很多表

image.png

这个面板对我们的job可以删除,所以生产环境的时候,必须加入权限验证

首先我们加入一个过滤器MyDashboardAuthorizationFilter.cs

using Hangfire.Dashboard;
using Microsoft.AspNetCore.Http;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;

namespace HangfireWeb
{
    public class MyDashboardAuthorizationFilter : IDashboardAuthorizationFilter
    {
        public bool Authorize([NotNull] DashboardContext context)
        {
            var httpContext = context.GetHttpContext();

            var header = httpContext.Request.Headers["Authorization"];

            if (string.IsNullOrWhiteSpace(header))
            {
                SetChallengeResponse(httpContext);
                return false;
            }

            var authValues = System.Net.Http.Headers.AuthenticationHeaderValue.Parse(header);

            if (!"Basic".Equals(authValues.Scheme, StringComparison.InvariantCultureIgnoreCase))
            {
                SetChallengeResponse(httpContext);
                return false;
            }

            var parameter = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(authValues.Parameter));
            var parts = parameter.Split(':');

            if (parts.Length < 2)
            {
                SetChallengeResponse(httpContext);
                return false;
            }

            var username = parts[0];
            var password = parts[1];

            if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
            {
                SetChallengeResponse(httpContext);
                return false;
            }

            if (username == "admin" && password == "123456")
            {
                return true;
            }

            SetChallengeResponse(httpContext);
            return false;
        }

        private void SetChallengeResponse(HttpContext httpContext)
        {
            httpContext.Response.StatusCode = 401;
            httpContext.Response.Headers.Append("WWW-Authenticate", "Basic realm=\"Hangfire Dashboard\"");
            httpContext.Response.WriteAsync("Authentication is required.");
        }
    }
}

然后我修改startup.cs管道:将app.UseHangfireDashboard(); 改一下

            app.UseHangfireDashboard("/hangfire", new Hangfire.DashboardOptions
            {
                Authorization = new[] { new MyDashboardAuthorizationFilter() }
            });

然后刷新我们的localhost:5050/hangfire,就会看到输入账户密码的弹框,账户密码就是我们过滤器中写死的,生产环境中可以读取数据库。

到此,我们的基本搭建都完成了,接下来我们正式开始介绍如何使用Hangfire


首先介绍一下,Hangfire有四种基本的用法。

-Fire-and-forget:任务队列,很多任务都加入队列,任务会被依次执行。Hangfire默认是加入default队列,你也可以配置多个队列。

-Delayed:延迟任务,会在指定时间之后执行。

-Recurring:周期任务,支持corn表达式,指定时间循环执行(用的最多)。

-Continuations:工作流任务,比如第二个任务执行条件,需要第一个任务的执行结果这种。


一、任务队列(Fire-and-forget)

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

Console.WriteLine("Fire-and-forget")是个方法和参数,你可以直接修改成你的方法和入参即可。

这句代码你写在哪里都可以,写在控制器或者startup类中,只要调用一次,就给队列加入了一次任务。

比如我们创建订单的时候,瞬间好几千万订单量进来,我们入库的动作就可以用这个调度来执行,Hangfire会依次入库。


二、延迟任务(Delayed)

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

比如我们的支付系统,支付完成,通知业务系统支付结果,第一次通知没成功,我可以等待5秒钟,再次通知。


三、周期任务(Recurring)

RecurringJob.AddOrUpdate("job1", () => TaskAction("1"), "0/10 * * * * ?");

这个周期任务和我们之前介绍的Quartz几乎效果一样,只是Hangfire调度更加方便,一句代码就可以创建一个周期任务。

比如我们每个月都要发一次通知,我们就可以设置corn表达式,每个月执行一次,然后这句代码只需要在startup类中调用一次,就可以了。

只要我的任务id,就是那个job1,不变,我可以再次用代码更新我的调度程序。非常的方便。


四、工作流任务(Continuations)

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

大家看以上代码,第一句是一个队列任务,第二句是工作流任务,他在等待第一个任务执行完成。


到这里,我们就讲解完了,我相信如果你认真看完这篇文章,你对Hangfire会有个大概的了解。

CarsonIT 微信扫码关注公众号 策略、创意、技术

留下您的脚步

 

最近评论

查看更多>>

热点推荐

友情打赏

请打开您的微信,扫一扫