Hangfire 是一个和 Quartz.Net 差不多的库,但是比较好的是 Hangfire 提供了web界面。 我的需求很简单,简单的一个控制台中能替代 Quartz.Net 执行任务。

开发环境

VS 2019 / .NET Framework 4.6.2

Demo构建

需要如下 Nuget 包

1
2
3
4
5
Install-Package Microsoft.AspNet.WebApi.OwinSelfHost
Install-Package Microsoft.Owin.Diagnostics
Install-Package Microsoft.Owin.Host.SystemWeb
Install-Package Hangfire
Install-Package Hangfire.Console

如果是非持久化存储,则安装

1
Install-Package Hangfire.MemoryStorage  

持久化的话官方有提供数据库和Redis的选项,但是Redis是收费选项。
这里可以用开源版本来替代

1
Install-Package Hangfire.Redis.StackExchange

Program.cs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
        private static void Main(string[] args)
        {
            // Redis 配置
            var redisOption = new RedisStorageOptions()
            {
                Db = 10,
                Prefix = "TestA:"
            };
            // 使用Redis存储
            GlobalConfiguration.Configuration.UseRedisStorage("127.0.0.1", redisOption);
            // 注册一个计划任务
            RecurringJob.AddOrUpdate("输出时间", (() => JobCenter.JobA()), Cron.Minutely);
            // 注册个OWIN 可以在本机开启控制台
            StartOptions options = new StartOptions();
            options.Urls.Add("http://localhost:9095");
            WebApp.Start<Startup>(options);
            // 阻止控制台关闭
            Thread.Sleep(Timeout.Infinite);
        }

Startup.cs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
using Hangfire;
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(ConsoleApp1.Startup))]
namespace ConsoleApp1
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // 有关如何配置应用程序的详细信息,请访问 https://go.microsoft.com/fwlink/?LinkID=316888
            app.UseHangfireDashboard();
            app.UseHangfireServer();
        }
    }
}

调试

启动控制台,可见计划任务开始执行了。

打开网页 http://localhost:9095/hangfire

可以看见计划任务的执行记录,带入参数等。

执行模式

Hangfire 的执行模式免费的状态下有4种

Fire-and-forget 立即执行

1
BackgroundJob.Enqueue(() => Console.WriteLine("Hello, world!"));

单次执行咯…

Schedule 周期任务

1
BackgroundJob.Schedule((() => Console.Write(".")), TimeSpan.FromMinutes(1));

这个模式会根据时间间隔重复执行任务。

Crontab 计划任务

1
2
RecurringJob.AddOrUpdate("输出时间", (() => JobCenter.JobA()), Cron.Minutely);
RecurringJob.AddOrUpdate("输出时间", (() => JobCenter.JobA()), "0 */1 * ? * *");

在这种模式下,可以设置Job的名称。这个名称可以在控制台中看见,字段是”编号“。
目前用的最多的应该就这种模式了。

ContinueJobWith 连续性任务

1
2
            var jobId = BackgroundJob.Enqueue(() => Thread.Sleep(1000));
            BackgroundJob.ContinueJobWith(jobId, () => Console.WriteLine("完成"));

这种模式是通过获取上个任务的ID,当上个任务完成后执行任务。

任务的异常处理

任务异常处理可以通过在方法上增加修饰器来进行。

1
2
3
4
5
6
7
8
 public class JobCenter
    {
        [AutomaticRetry(Attempts = 5)]
        public static void JobA()
        {
            Debug.WriteLine(DateTime.Now);
        }
    }

其中的

1
[AutomaticRetry(Attempts = 5)]

就是当异常出现时,自动重试,当达到5次失败后抛出异常。
AutomaticRetry的重试次数预设为10次,如果不想重试可以直接设置为0。
如果想要全局设置这个重试次数,可以使用

1
GlobalJobFilters.Filters.Add(new AutomaticRetryAttribute { Attempts = 5 });

AutomaticRetry中还有很多参数,例如这种

1
 [AutomaticRetry(Attempts = 5 ,DelaysInSeconds = new[] { 3, 10, 15 }, OnAttemptsExceeded = AttemptsExceededAction.Delete)]

DelaysInSeconds 指定了重试的时间间隔
OnAttemptsExceeded 当失败后的操作,是归类到删除还是失败

同时在控制台中,也可很清晰的看见异常的信息

Queue设定

Queue的命名规则:小写字母,数字,下划线和破折号
当配置Queue名称后,UseHangfireServer 中也需要传入名称才能使用。

其他

并发限制

1
[DisableConcurrentExecution(秒数)]

任务名称

1
[JobDisplayName("名字")]