zoukankan      html  css  js  c++  java
  • Hangfire 在asp.net core环境的使用

    hf被定义为分布式后台服务,更加类似job作业的服务
    做作业的插件有quartz.net,JobScheduler 等
    当然,都有一些分别和适用的场景。
    1.安装
    需要安装
    Hangfire.Core
    Hangfire.AspNetCore
    Hangfire.SqlServer
    关于数据库存储工具,可以根据场景去选择安装
    例如mysql 的,需要安装 Hangfire.MySql (mysql很多第三方写,所以使用时主要使用环境)
    Redis放入 Hangfire.Redis
    redis是官方作者去更新,所以这些使用可以直接看官网
    2.配置
    asp.net core主要是startup配置DI组件。
    官网也有说,列举一下

      // Add Hangfire services.
                services.AddHangfire(configuration => configuration
               .SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
               .UseSimpleAssemblyNameTypeSerializer()
               .UseRecommendedSerializerSettings()
               .UseSqlServerStorage(Configuration.GetConnectionString("default"), new SqlServerStorageOptions
               {
                   CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
                   SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
                   QueuePollInterval = TimeSpan.Zero,
                   UseRecommendedIsolationLevel = true,
                   UsePageLocksOnDequeue = true,
                   DisableGlobalLocks = true
               }));
    
          services.AddHangfireServer();

    关键是这个链如何配,UseSqlServerStorage专门读取hangfire会写入哪个数据库,如果用现在的业务数据库,hangfire的表会写进去的,也可以设计分开来存放,例如hangfire的DB,集中去管理。当然一般小的项目,直接跟业务数据库,集中而独立的架构。

    Configure里面的配置

    var jobOptions = new BackgroundJobServerOptions
                {
                    Queues = new[] { "back", "front", "default" },//队列名称,只能为小写
                    WorkerCount = Environment.ProcessorCount * 5, //并发任务数
                    ServerName = "conference hangfire1",//服务器名称
                };
    
                app.UseHangfireServer(jobOptions);//启动Hangfire服务
    
                app.UseHangfireDashboard();//启动hangfire面板
                backgroundJobs.Enqueue(() => Console.WriteLine("Hangfire 服务器已启动"));
    
                app.UserHangfireAdminService(service); //这个是自己写的服务扩展

    jobOptions如果不配置,会有自己默认的名称,例如服务器会读取你当前系统的名称,队列那些会读取对应服务器的程序集名称。

    3.写服务

    完成了第一二步,这里看这个作业如何写

    public static class HangfireAdminService
        {
            private static BackgroundJobServer _server;
    
            /// <summary>
            /// 使用后台作业
            /// </summary>
            /// <param name="app"></param>
            /// <param name="service"></param>
            /// <param name="client"></param>
            /// <returns></returns>
            public static IApplicationBuilder UserHangfireAdminService(this IApplicationBuilder app,
                IConferenceService service)
            {
                var mcfg = service.MailConfigDefault();
                BackgroundJob.Enqueue(() => Console.WriteLine($"测试单个作业: {DateTime.Now}"));
                RecurringJob.AddOrUpdate(
                    () =>
                   Console.WriteLine($"测试循环作业: {DateTime.Now}"), Cron.Minutely
                );
    
                BackgroundJob.Schedule(() => Console.WriteLine($"测试延迟作业: {DateTime.Now}"), TimeSpan.FromMinutes(1));
    
                return app;
            }
        }

    这个是刚才configure里面的方法。 可以写成一个IApplicationBuilder的扩展方法,加进管道
    这样服务器启动时,就会启动里面的服务。
    如果Job作业需要调用一个后台服务,就不能直接在里面_service.Log这样去调用方法了,因为处于不同的线程方式。所以job调后台,可以这样操作
    举例,这是个api发邮件的方法

    /// <summary>
            /// 发送邮件
            /// </summary>
            /// <param name="mail"></param>
            [HttpPost]
            [Route("SendPwd")]
            public MsgResult<bool> SendPwd(MailConfigDto mail)
            {
                MsgResult<bool> result = new MsgResult<bool>(ResultCode.Success);
                UserAccountDto user = null;
                try
                {
                    MailConfigDto defaultMail = _service.MailConfigDefault();
    
                    user = _service.UserDtoById(mail.ExtensionId);
                    defaultMail.Body = $"用户注册成功!登录名是:{user.UserName},登录密码是:{user.Password},注册类型是:{user.CustomerProfileName}";
                    defaultMail.Subject = $"用户:{user.Name}注册成功!";
                    List<KeyValuePair<string, string>> To = new List<KeyValuePair<string, string>>() {
                        new KeyValuePair<string, string>(user.Name,user.Email)
                    };
                    defaultMail.To = To;
                    SendEmail(defaultMail);
                    BackgroundJob.Enqueue<IConferenceService>((s) =>
                     s.LogAdd("注册成功", $"用户{user.Name}注册成功,已发送邮件", OPLog.AdminLogin)
                      );
                }
                catch (Exception ex)
                {
                    result = new MsgResult<bool>(ResultCode.Exception, ex.Message);
                }
    
                return result;
    
            }

    关键点, BackgroundJob.Enqueue<IConferenceService>((s) =>s.LogAdd());
    Enqueue有个泛型的重载,这里等于是依赖注入的方式,因为在全局autofac配置过
    IConferenceService是指向ConferenceService服务的,所以这里注入了Enqueue<IConferenceService>接口,只能是接口,才可以让DI生效。
    so, s.LogAdd代表了接口里面的方法。这样Enqueue里面就可以调用后台自定义的服务了

    4.总结,当然还有很多细节没谈,不过这样基本的配置和使用,已经满足软件的日常用途了。
    补充一点,常用的三种方式的特点,
    立即执行,完事后会自动销毁,当然,失败了按默认的1分钟后会重新尝试,直到成功了
    延迟执行,这个等于制定了计划的执行时间,这里最少时间是按分钟算,所以这里不能按用秒甚至毫秒做计算时间的任务。
    循环执行,循环执行独立一个方法 RecurringJob。如果大类分,前2个是一个后台作业类,这个独立的类。循环执行某次进程如果失败了,也不会影响整体的循环效果,只是失败的进程也会按总体的规则,1分钟后重新尝试失败的进程。

    当然还有其他的,例如批量处理,延续,批量延续等

  • 相关阅读:
    全链路压测(4):全链路压测的价值是什么?
    基于SVN的版本范围汇总
    一篇值得思考的职业教育之路!
    分享35个讨人喜欢的漂亮进度条UI设计
    转一篇难得的好文章CPU流水线的探秘之旅
    超棒的获奖动物摄影作品集
    解决web.py在SAE云中的Session使用问题
    2012年度最新免费web开发设计资源荟萃
    Endless icon: 每天都更新的图标集
    不容错过的超棒Javascript日期处理类库Moment.js
  • 原文地址:https://www.cnblogs.com/drek_blog/p/10795071.html
Copyright © 2011-2022 走看看