什么是HangfireHangfire
一个开源的.NET任务调度框架,目前1.6+版本已支持.NET Core。个人认为它最大特点在于内置提供集成化的控制台,方便后台查看及监控,如下图:
Jucheap3.0中用到的技术
Hangfire
Hangfire.SqlServer
Hangfire.SimpleInjector
Hangfire.Console
在使用Hangfire的时候需要注意一点,Hangfire的Cron表达式暂时只支持到分钟级别的循环任务。
本实例中,主要用了3个定时任务来做demo
1.定时发送带附件的邮件
2.定时抓取指定几个网站的代理ip信息,并存放到本地数据库
3.定时验证抓取到的代理ip地址,是否有效
基本配置代码如下:
using System;
using System.Linq;
using System.Reflection;
using Hangfire;
using Hangfire.Console;
using Hangfire.SimpleInjector;
using Hangfire.SqlServer;
using JuCheap.Interfaces.Task;
using Owin;
using SimpleInjector.Extensions.ExecutionContextScoping;
namespace JuCheap.Web
{
public partial class Startup
{
/// <summary>
/// 配置Hangfire
/// </summary>
/// <param name="app"></param>
public void ConfigureHangfire(IAppBuilder app)
{
JobIocConfig.Register();
//Hangfire IOC配置
GlobalConfiguration.Configuration.UseActivator(new SimpleInjectorJobActivator(JobIocConfig.Container));
//hangfire 配置
//使用SQLServer作为 数据库存储
var storage = new SqlServerStorage("JuCheap-Job");
GlobalConfiguration.Configuration.UseStorage(storage).UseConsole();
GlobalJobFilters.Filters.Add(new AutomaticRetryAttribute { Attempts = 0 });
//OWIN-based authentication
var options = new DashboardOptions
{
Authorization = new[]
{
new HangfireAuthorizationFilter()
}
};
app.UseHangfireDashboard("/taskcenter", options);
LoadRecurringTasks();
var jobOptions = new BackgroundJobServerOptions
{
ServerName = Environment.MachineName
};
app.UseHangfireServer(jobOptions);
}
/// <summary>
/// 加载Job
/// </summary>
public static void LoadRecurringTasks()
{
using (JobIocConfig.Container.BeginExecutionContextScope())
{
var types = from type in Assembly.Load("JuCheap.Services").GetTypes()
where
type.Namespace?.StartsWith("JuCheap.Services.TaskServices") == true &&
type.GetInterfaces().Any(t => t == typeof(IRecurringTask))
select type;
foreach (var type in types)
{
var task = JobActivator.Current.ActivateJob(type) as IRecurringTask;
if (task == null)
{
continue;
}
if (task.Enable)
{
RecurringJob.AddOrUpdate(task.JobId, () => task.Excute(null), task.CronExpression, timeZone: TimeZoneInfo.Local);
}
else
{
RecurringJob.RemoveIfExists(task.JobId);
}
}
}
}
}
}