• .NET Core 3.1 + Hangfire 配置以及踩坑


    起初在基于ABP开发的个人博客中尝试过使用Hangfire构建后台任务服务,期间配置相对简单,毕竟ABP做了相应的拓展。现在常规的.NET Core 3.1框架下进行集成使用,并且是基于MySql 5.6,并对遇到的问题进行一个汇总。

    集成Hangfire

    构建完成后整个系统的结构:

    添加后台任务层

    1、在后台任务层中添加Hangfire Nuget 包

    1、Hangfire.AspNetCore
    2、Hangfire.Core
    3、Hangfire.Dashboard.BasicAuthorization
    4、Hangfire.MySql.Core
    

    如上图所示,添加一个以BackgroundJobs结尾的程序集,进行对后台任务接口、实现的分离。

    其中主要有任务接口、对应实现以及常用的Cron定义

    2、任务接口:IBackgroundJob

     public interface IBackgroundJob
        {
            /// <summary>
            /// 执行任务
            /// </summary>
            /// <returns></returns>
            Task ExecuteAsync();
        }
    

    3、任务实现:HangfireTestJob

     public class HangfireTestJob : IBackgroundJob
        {
            public async Task ExecuteAsync()
            {
                Console.WriteLine("定时任务测试");
                await Task.CompletedTask;
            }
        }
    

    4、常用的Cron:JobCronType

    主要定义一些常用的Cron,静态方法返回Cron 字符串

    5、将任务实现注入到Autofac容器中

     public void ConfigureContainer(ContainerBuilder builder)
            {
                builder.RegisterAssemblyTypes(Assembly.LoadFrom(backgroundJob))//后台任务
                       .Where(a=>a.IsClass )
                       .InstancePerDependency();
            }
    

    服务注册与添加中间件

    1、配置Hang服务、中间件拓展

    这块采用添加拓展服务的形式添加Hangfire服务,让Startup更简洁,代码如下:

    public static void AddHangfireService(this IServiceCollection services )
            {
                services.AddHangfire(options =>
                {
                    options.UseStorage(
                        new MySqlStorage(AppSettings.ConnectionString,//配置连接字符串,连接字符串需要加入Allow User Variables=true;配置
                        new MySqlStorageOptions
                        {
                            TablePrefix = "ps_hangfire"//配置表名前缀
                            }));
                });
            }
    

    采用扩展的形式配置Hangfire中间件:

     public static void UseHangfireMiddleware(this IApplicationBuilder app, ILifetimeScope lifetimeScope)
            {
                app.UseHangfireServer();//添加hangfire服务中间件
                app.UseHangfireDashboard(options: new DashboardOptions
                {
                    Authorization = new[] {new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions
                    {
                        RequireSsl = false,//需要SSL连接才能访问HangFire Dahsboard。
                        SslRedirect = false,//是否将所有非SSL请求重定向到SSL URL
                        LoginCaseSensitive = true,//区分大小写
                        Users = new []//用户
                        {
                            new BasicAuthAuthorizationUser
                            {
                                Login = AppSettings.Hangfire.Login,
                                PasswordClear = AppSettings.Hangfire.Password
                            },
                        }
                    }), },
                    DashboardTitle = "任务调度中心"
                });//添加hangfire仪表盘中间件,添加登陆认证
    
                HangfireService(lifetimeScope);//配置各个任务
            }
    
            private static void HangfireService(ILifetimeScope lifetimeScope)
            {
                var job = lifetimeScope.Resolve<HangfireTestJob>();//获取容器实例(记得的要注入任务实现)
                RecurringJob.AddOrUpdate("定时任务测试", () => job.ExecuteAsync(), JobCronType.Minute());
            }
    

    2、添加服务、中间件

     public void ConfigureServices(IServiceCollection services)
            {
                 #region Hangfire注册
    
                services.AddHangfireService();
    
                #endregion
            }
    
     public void Configure(IApplicationBuilder app, IWebHostEnvironment env ,ILifetimeScope lifetimeScope)
            {
         		app.UseHangfireMiddleware(lifetimeScope);//添加Hangfire中间件
     		}
    

    出现的问题

    问题有2个,一个是对于连接数据库MySql5.6引发的问题,另一个是问题是个人对Autofac依赖注入的不了解导致的。

    问题(一):在配合MySql5.6使用时,运行报错

    问题分析:在配置完成后,启动项目,Hangfire在创建所需要的表时失败,提示“Index column size too large. The maximum column size is 767 bytes.”,再次启动时,会发现再次报错为缺少名为“前缀_set ”的表。从错误信息中可看出,是INNODB 引擎,UTF-8,主键字符串 默认最大 767,所以导致报错,进而导致生成的表不完全。

    解决方案:

    首先需要对数据库进行如下设置:

    SET GLOBAL INNODB_LARGE_PREFIX = ON;
    SET GLOBAL innodb_file_format = BARRACUDA;
    

    并进行查看是否生效:

    SHOW variables like 'innodb_large_prefix';
    SHOW variables like 'innodb_file_format';
    

    最后,需要手动的创建者几个缺少的表([前缀]_set、[前缀]_State、[前缀]_Job):

    注意修改为自己的前缀

    CREATE TABLE `ps_hangfire_Set` (
     `Id` int(11) NOT NULL AUTO_INCREMENT,
     `Key` varchar(100) NOT NULL,
     `Value` varchar(256) NOT NULL,
     `Score` float NOT NULL,
     `ExpireAt` datetime DEFAULT NULL,
     PRIMARY KEY (`Id`),
     UNIQUE KEY `IX_Set_Key_Value` (`Key`,`Value`)
    ) ENGINE=InnoDB  CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
    
    CREATE TABLE `ps_hangfire_State`
    (
    	Id int(11) NOT NULL AUTO_INCREMENT,
    	JobId int(11) NOT NULL,
    	Name varchar(20) NOT NULL,
    	Reason varchar(100) NULL,
    	CreatedAt datetime NOT NULL,
    	Data longtext NULL,
    	PRIMARY KEY (`Id`),
    	KEY `FK_HangFire_State_Job` (`JobId`)
    ) ENGINE=InnoDB  CHARSET=utf8mb4;
    
    CREATE TABLE `ps_hangfire_List`
    (
    	`Id` int(11) NOT NULL AUTO_INCREMENT,
    	`Key` varchar(100) NOT NULL,
    	`Value` longtext NULL,
    	`ExpireAt` datetime NULL,
    	PRIMARY KEY (`Id`)
    ) ENGINE=InnoDB  CHARSET=utf8mb4;
    

    问题(二):Autofac注册任务后无法获取到实例

    问题分析:在Autofac注入时,我采用了程序集注入的形式注入,如下:

    var backgroundJob = Path.Combine(basePath,"PaymentStatistics.BackgroundJobs.dll");
    builder.RegisterAssemblyTypes(Assembly.LoadFrom(backgroundJob))//后台任务
                      .AsImplementedInterfaces()
                      .InstancePerDependency();
    

    结果通过以下方式愣是拿不到实例:

    var job = lifetimeScope.Resolve<HangfireTestJob>();
    

    最后才发现,自己采用的是接口注册的方式进行注册,用实现类根本拿不到,只用用对应接口才能够拿到:

    var job = lifetimeScope.Resolve<IBackgroundJob>();
    

    但是,这么拿也不对,毕竟我是一个接口,对应多个实例,这样只能拿一个。

    解决方案:

    采用实例的注册方式,这样就能通过实现类去获取实例:

    var backgroundJob = Path.Combine(basePath,"PaymentStatistics.BackgroundJobs.dll");
    builder.RegisterAssemblyTypes(Assembly.LoadFrom(backgroundJob))//后台任务
                      .Where(a=>a.IsClass )
                      .InstancePerDependency();
    
  • 相关阅读:
    DFS
    离散化
    前缀和&差分
    数组运用_1-15 选择题
    数组运用_1-13 选择题
    数组运用_1-11 选择题
    数组运用_1-9 选择题
    数组运用_1-4 编程练习
    数组初始_2-22编程练习
    poj 3669 bfs(这道题隐藏着一个大坑)
  • 原文地址:https://www.cnblogs.com/memoyu/p/13955094.html
Copyright © 2020-2023  润新知