.NET之Hangfire快速入门和使用

什么是Hangfire

Hangfire是一个开源且商业免费使用的工具函数库。可以让你非常容易地在ASP.NET应用(也可以不在ASP.NET应用)中执行多种类型的后台任务,而无需自行定制开发和管理基于Windows Service后台任务执行器。且任务信息可以被持久保存。内置提供集成化的控制台。

Hangfire的基本特征与优点

与quartz.net对比

很大的原因在于项目需要一个后台可监控的应用,不用每次都要从服务器拉取日志查看,在没有ELK的时候相当不方便。Hangfire控制面板不仅提供监控,也可以手动的触发执行定时任务

 

HangFire例子

1、新建项目

2、引用安装

 

这里我们选择redis 作为持久化方式,所以引用

Hangfire.Redis.StackExchange.StrongName

配置面板、redis链接

Startup.cs

 

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews().AddControllersAsServices();
            GlobalStateHandlers.Handlers.Add(new SucceededStateExpireHandler(int.Parse(Configuration["Hangfire:JobExpirationTimeout"])));
            services.AddHostedService<RecurringJobsService>();
            services.AddHangfire(x =>
            {
                var connectionString = Configuration["Hangfire:Redis:ConnectionString"];
                x.UseRedisStorage(connectionString, new RedisStorageOptions()
                {
                    //活动服务器超时时间
                    InvisibilityTimeout = TimeSpan.FromMinutes(60),
                    Db = int.Parse(Configuration["Hangfire:Redis:Db"])
                });
                x.UseDashboardMetric(DashboardMetrics.ServerCount)
                    .UseDashboardMetric(DashboardMetrics.RecurringJobCount)
                    .UseDashboardMetric(DashboardMetrics.RetriesCount)
                    .UseDashboardMetric(DashboardMetrics.AwaitingCount)
                    .UseDashboardMetric(DashboardMetrics.EnqueuedAndQueueCount)
                    .UseDashboardMetric(DashboardMetrics.ScheduledCount)
                    .UseDashboardMetric(DashboardMetrics.ProcessingCount)
                    .UseDashboardMetric(DashboardMetrics.SucceededCount)
                    .UseDashboardMetric(DashboardMetrics.FailedCount)
                       .UseDashboardMetric(DashboardMetrics.EnqueuedCountOrNull)
                          .UseDashboardMetric(DashboardMetrics.FailedCountOrNull)
                    .UseDashboardMetric(DashboardMetrics.DeletedCount);
            });
        }

配置面板登录权限、作业通道

 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
            app.UseStaticFiles();

            app.UseRouting();
            app.UseAuthorization();
            var filter = new BasicAuthAuthorizationFilter(
        new BasicAuthAuthorizationFilterOptions
        {
            SslRedirect = false,
            RequireSsl = false,
            LoginCaseSensitive = false,
            Users = new[]
            {
                        new BasicAuthAuthorizationUser
                        {
                            Login = Configuration["Hangfire:Login"] ,
                            PasswordClear= Configuration["Hangfire:PasswordClear"]
                        }
            }
        });
            app.UseHangfireDashboard("", new DashboardOptions
            {
                Authorization = new[]
                {
                   filter
                },
            });
            var jobOptions = new BackgroundJobServerOptions
            {
                Queues = new[] { "critical", "test", "default" },
                WorkerCount = Environment.ProcessorCount * int.Parse(Configuration["Hangfire:ProcessorCount"]),
                ServerName = Configuration["Hangfire:ServerName"],
                SchedulePollingInterval = TimeSpan.FromSeconds(1), //计划轮询间隔  支持任务到秒
            };
            app.UseHangfireServer(jobOptions);
        }
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "Hangfire": {
    "Redis": {
      "ConnectionString": "localhost:6379,password=123456,abortConnect=false",
      "Db": 10
    },
    "Login": "admin", //账号
    "PasswordClear": "123456", //密码
    "ServerName": "hangfire001", //站点服务名称
    "JobExpirationTimeout": 1, //成功job过期时间 分钟
    "ProcessorCount": 5 //线程数
  },
  "AllowedHosts": "*"
}

使用作业

using Hangfire;
using Hangfire.Server;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using TestService;

namespace hangfiretest.RecurringJobs
{
    internal class RecurringJobsService : BackgroundService
    {
        private readonly IBackgroundJobClient _backgroundJobs;
        private readonly IRecurringJobManager _recurringJobs;
        private readonly ILogger<RecurringJobScheduler> _logger;
        public Itest _test { get; set; }

        public RecurringJobsService(
            [NotNull] IBackgroundJobClient backgroundJobs,
            [NotNull] IRecurringJobManager recurringJobs,
            [NotNull] ILogger<RecurringJobScheduler> logger)
        {
            _backgroundJobs = backgroundJobs ?? throw new ArgumentNullException(nameof(backgroundJobs));
            _recurringJobs = recurringJobs ?? throw new ArgumentNullException(nameof(recurringJobs));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            try
            {
                _recurringJobs.AddOrUpdate<Itest>("seconds", i => _test.demo(), "*/1 * * * * *", queue: "critical");
                //_backgroundJobs.Enqueue<Services>(x => x.LongRunning(JobCancellationToken.Null));
                //_recurringJobs.AddOrUpdate("seconds", () => Console.WriteLine("Hello, seconds!"), "*/15 * * * * *");
                //_recurringJobs.AddOrUpdate("minutely", () => Console.WriteLine("Hello, world!"), Cron.Minutely);
                //_recurringJobs.AddOrUpdate("hourly", () => Console.WriteLine("Hello"), "25 15 * * *");
                //_recurringJobs.AddOrUpdate("neverfires", () => Console.WriteLine("Can only be triggered"), "0 0 31 2 *");
                //_recurringJobs.AddOrUpdate("Hawaiian", () => Console.WriteLine("Hawaiian"), "15 08 * * *", TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time"));
                //_recurringJobs.AddOrUpdate("UTC", () => Console.WriteLine("UTC"), "15 18 * * *");
                //_recurringJobs.AddOrUpdate("Russian", () => Console.WriteLine("Russian"), "15 21 * * *", TimeZoneInfo.Local);
            }
            catch (Exception e)
            {
                _logger.LogError("An exception occurred while creating recurring jobs.", e);
            }

            return Task.CompletedTask;
        }
    }
}

已完成的job设置过期,防止数据无限增长

using Hangfire.States;
using Hangfire.Storage;
using System;

namespace hangfiretest
{
    /// <summary>
    /// 已完成的job设置过期,防止数据无限增长
    /// </summary>
    public class SucceededStateExpireHandler : IStateHandler
    {
        public TimeSpan JobExpirationTimeout;

        public SucceededStateExpireHandler(int jobExpirationTimeout)
        {
            JobExpirationTimeout = TimeSpan.FromMinutes(jobExpirationTimeout);
        }

        public string StateName => SucceededState.StateName;

        public void Apply(ApplyStateContext context, IWriteOnlyTransaction transaction)
        {
            context.JobExpirationTimeout = JobExpirationTimeout;
        }

        public void Unapply(ApplyStateContext context, IWriteOnlyTransaction transaction)
        {
        }
    }
}

RUN起来

是不是很简单啊,以前我是使用quartz,自从使用了hangfire,反正我是再也不想在使用quartz;有点类似git和svn的关系;

 

完整代码:

https://github.com/conanl5566/mydemo/tree/master/hangfire/hangfire.demo

 

 

 

原文地址:https://www.cnblogs.com/lyl6796910/p/13767128.html