Skip to content

00.QickStart

俞正东 edited this page Dec 2, 2022 · 12 revisions

先介绍下Hangfire.HttpJob自身引用的组件

  • Hangfire.AspNetCore (因为Hangfire.HttpJob是作为Hangfire的插件,Hangfire.AspNetCore是Hangfire的核心组件)
  • Hangfire.Console (Hangfire.Console是Hangfire的Dashbord的一个插件,记录job运行日志的)
  • Hangfire.Tags (这个是Hangfire的Dashbord的一个插件,把运行的job按照名称进行分组在dashbord里面方便查看)
  • HttpClientFactory (由于Hangfire.HttpJob是用web HttpClient的方式进行job调用的,所以使用我开源的HttpCientFactory组件可以规避HttpCliet使用上的一些坑点)
  • MailKit (Hangfire.HttpJob支持job运行失败或者成功发送邮件通知)
  • Newtonsoft.Json (这个不用介绍了)

这里测试用Mysql作为hangfire的存储。如果用SqlServer可以参考wiki的介绍

代码可以参考工程的Demo目录(里面有mysql,redis,sqlserver三种存储类型的demo) nuget引用如下包:

  • Hangfire.HttpJob
  • Hangfire.Tags.MySql.Official (这个是开源的一个针对Hangfire.Tags的mysql存储)
  • Hangfire.MySqlStorage (这个是Hangfire本身的mysql存储实现)
  • Hangfire.Dashboard.BasicAuthorization (这个是Hangfire的auth认证组件)

我这里用Nlog记录日志

NLog.Extensions.Logging


 public class Startup
    {
       
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddHangfire(Configuration);//Configuration是下面的方法
        }
        private void Configuration(IGlobalConfiguration globalConfiguration)
        {
            var mysqlOption =  new MySqlStorageOptions //这个是mysqlstorage的相关配置
            {
                TransactionIsolationLevel = IsolationLevel.ReadCommitted,
                QueuePollInterval = TimeSpan.FromSeconds(15),
                JobExpirationCheckInterval = TimeSpan.FromHours(1),
                CountersAggregateInterval = TimeSpan.FromMinutes(5),
                PrepareSchemaIfNecessary = true,
                DashboardJobListLimit = 50000,
                TransactionTimeout = TimeSpan.FromMinutes(1),
                TablePrefix = "hangfire_"
            }
            globalConfiguration.UseStorage(new MySqlStorage("HangfireMysqlConnectionString",mysqlOption))
                .UseConsole(new ConsoleOptions()
                {
                    BackgroundColor = "#000079"
                })
                .UseHangfireHttpJob(new HangfireHttpJobOptions
                {
                    //你如果不使用这个使用钉钉也是可以的 看wiki里面关于使用钉钉通知的介绍
                    MailOption = new MailOption
                    {
                        Server = "smtp.qq.com",
                        Port = 465,
                        UseSsl = true,
                        User = "1877682825@qq.com",
                        Password = "test",
                    },
                    DefaultRecurringQueueName = "recurring" //这个是在下面设置的queue列表中的其中一个
                })
               .UseTagsWithMysql(sqlOptions: mysqlOption);
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory logging)
        {
            #region NLOG 你不用NLOG也可以去掉
            NLog.LogManager.LoadConfiguration("NLog.Config");
            logging.AddNLog();
            #endregion


            //强制显示中文
            System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("zh-CN");

            //强制显示英文
            //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("");

        

            var queues = new List<string> {"default","apis","recurring"};
            app.UseHangfireServer(new BackgroundJobServerOptions
            {
                ServerTimeout = TimeSpan.FromMinutes(4),
                SchedulePollingInterval = TimeSpan.FromSeconds(15),//秒级任务需要配置短点,一般任务可以配置默认时间,默认15秒
                ShutdownTimeout = TimeSpan.FromMinutes(30),//超时时间
                Queues = queues,//队列
                WorkerCount = Math.Max(Environment.ProcessorCount, 40)//工作线程数,当前允许的最大线程,默认20
            });

            var hangfireStartUpPath = "/job";
            app.UseHangfireDashboard(hangfireStartUpPath, new DashboardOptions
            {
                AppPath = "#",
                IgnoreAntiforgeryToken = true,//这里一定要写true 不然用client库写代码添加webjob会出错
                DisplayStorageConnectionString = false,
                IsReadOnlyFunc = Context => false,
                Authorization = new[] { new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions
                {
                    RequireSsl = false,
                    SslRedirect = false,
                    LoginCaseSensitive = true,
                    Users = new []
                    {
                        new BasicAuthAuthorizationUser
                        {
                            Login = "admin",
                            PasswordClear =  "test"
                        }
                    }

                }) }
            });

            var hangfireReadOnlyPath = "/job-read";
            //只读面板,只能读取不能操作
            app.UseHangfireDashboard(hangfireReadOnlyPath, new DashboardOptions
            {
                AppPath = hangfireStartUpPath,//返回时跳转的地址
                DisplayStorageConnectionString = false,//是否显示数据库连接信息
                IsReadOnlyFunc = Context => true
            });

            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("ok.");
            });
        }
    }

注意: 如果没有在数据库里面创建一个db叫hangfire的话 会报错! 可以不创建hangfire的表 因为按照如上配置 启动程序会判断有没有叫hangfire的db。如果存在没有表会初始化hangfire的表!

按照以上配置 启动程序

浏览器打开 localhost:5000/job 就会打开hangfire的 dashbord image

image

浏览器打开 localhost:5000/job-read 就会打开hangfire的只读 dashbord 以上按钮将隐藏

以上代码在本仓库的Test里面有很详细的demo(包括sqlserver,mysql,redis三个版本),你配置好db后可以直接跑起来的

建议使用mysql作为存储的使用 https://github.com/MiloszKrajewski/Hangfire.Storage.MySql

官方推荐的版本有死锁的bug,有主键自增膨胀(归根到底还是没有控制好锁) 参考issue: