Hangfire
用法比较简单,也直接去官网看。这里直接说几种模式的用法。
项目示例
准备工作
1. 引入nuget包
Hangfire.AspNetCore
Hangfire.Dashboard.BasicAuthorization #用于Dashboard面板
Hangfire.SqlServer #我这里用的sqlserver,如果用其他的数据库存储就换成对应的扩展包
2. appsettings.json中添加配置
"HangfireConfig": {
"SslRedirect": false,
"RequireSsl": false,
"LoginCaseSensitive": false,
"Login": "fcbadmin",
"PasswordClear": "123456",
"ConnectionString": "Server=.\\sqlexpress;Database=HangfireTest;Integrated Security=SSPI;"
}
3. Program中添加服务注入配置
builder.Services.AddHangfire(configuration => configuration
//.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage(builder.Configuration.GetSection("HangfireConfig:ConnectionString").Value, new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
DisableGlobalLocks = true
}));
builder.Services.AddHangfireServer();
或者换种简单的
builder.Services.AddHangfire(config =>
{
config.UseStorage(new SqlServerStorage(Configuration.GetSection("HangfireConfig").GetValue<string>("ConnectionString")));
});
4. Program中添加Dashboard面板,这里添加了账号认证,如果觉得没有必要把配置取消就可以了
app.UseHangfireDashboard("/task", new DashboardOptions
{
Authorization = new[] {
new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions{
SslRedirect = builder.Configuration.GetSection("HangfireConfig").GetValue<bool>("SslRedirect"),
RequireSsl=builder.Configuration.GetSection("HangfireConfig").GetValue<bool>("RequireSsl"),
LoginCaseSensitive=builder.Configuration.GetSection("HangfireConfig").GetValue<bool>("LoginCaseSensitive"),
Users=new []{
new BasicAuthAuthorizationUser{
Login=builder.Configuration.GetSection("HangfireConfig").GetValue<string>("Login"),
PasswordClear=builder.Configuration.GetSection("HangfireConfig").GetValue<string>("PasswordClear")
}
}
})
},
});
准备工作完成了,下面就看几种模式用法
定时任务
/// <summary>
/// 执行定时任务。定期作业按指定的 CRON 计划触发多次。
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("Test_RecurringJob")]
public async Task<IActionResult> Test_RecurringJob()
{
//自动获取本地时区
RecurringJob.AddOrUpdate<ValuesController>("测试定时任务", x => x.TestRecurringJobContent(), Cron.MinuteInterval(10), TimeZoneInfo.Local);
////指定Windows时区
//RecurringJob.AddOrUpdate<ValuesController>("测试定时任务", x => x.TestRecurringJobContent(), Cron.MinuteInterval(2), TimeZoneInfo.CreateCustomTimeZone("China Standard Time", new TimeSpan(08, 00, 00), "China Standard Time", "China Standard Time"));
////指定Linux时区
//RecurringJob.AddOrUpdate<ValuesController>("测试定时任务", x => x.TestRecurringJobContent(), Cron.MinuteInterval(2), TimeZoneInfo.CreateCustomTimeZone("Asia/Shanghai", new TimeSpan(08, 00, 00), "Asia/Shanghai", "Asia/Shanghai"));
return Ok("执行成功");
}
/// <summary>
/// 执行定时任务
/// </summary>
/// <returns></returns>
public async Task<IActionResult> TestRecurringJobContent()
{
Console.WriteLine("执行了定时任务");
return Ok();
}
一次性作业
/// <summary>
/// 立即执行一次性作业。即发即弃作业仅在创建后立即执行一次。
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("Test_BackgroundJob_Enqueue")]
public async Task<IActionResult> Test_BackgroundJob_Enqueue()
{
var jobId = BackgroundJob.Enqueue(
() => Console.WriteLine("执行了立即执行一次性作业"));
return Ok("执行成功");
}
延迟作业
/// <summary>
/// 延迟作业。延迟的作业也只执行一次,但不会在一定时间间隔后立即执行。
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("Test_BackgroundJob_Schedule")]
public async Task<IActionResult> Test_BackgroundJob_Schedule()
{
var jobId = BackgroundJob.Schedule(
() => Console.WriteLine("执行了延迟作业"),
TimeSpan.FromMinutes(1));
return Ok("执行成功");
}
延续作业
/// <summary>
/// 延续作业。延续在其父作业完成时执行。
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("Test_BackgroundJob_ContinueJobWith")]
public async Task<IActionResult> Test_BackgroundJob_ContinueJobWith()
{
Console.WriteLine("开始等待,当前时间:" + DateTime.Now);
var jobId = BackgroundJob.Schedule(
() => Console.WriteLine("执行了2秒延迟作业,当前时间:"+DateTime.Now),
TimeSpan.FromSeconds(2));
BackgroundJob.ContinueJobWith(
jobId,
() => Console.WriteLine("在执行了2秒延迟作业之后,又执行了延续作业,当前时间:" + DateTime.Now));
return Ok("执行成功");
}
Quartz
Quartz.Net 官网:https://www.quartz-scheduler.net/
个人感觉没有hangfire好用,使用要稍微复杂一些,官方没有看到类似于hangfire中Dashboard的可视化界面,网上倒是很多人扩展了,可以直接用
核心接口
Scheduler - 与调度程序交互的主要API。
Job - 你想要调度器执行的任务组件需要实现的接口
JobDetail - 用于定义作业的实例。
Trigger(即触发器) - 定义执行给定作业的计划的组件。
JobBuilder - 用于定义/构建 JobDetail 实例,用于定义作业的实例。
TriggerBuilder - 用于定义/构建触发器实例。
Scheduler 的生命期,从 SchedulerFactory 创建它时开始,到 Scheduler 调用shutdown() 方法时结束;Scheduler 被创建后,可以增加、删除和列举 Job 和 Trigger,以及执行其它与调度相关的操作(如暂停 Trigger)。但是,Scheduler 只有在调用 start() 方法后,才会真正地触发 trigger(即执行 job)
准备工作
1. 引入nuget包
Quartz
2. Program中添加服务注入配置,这里没有集成数据库
builder.Services.AddScoped<ISchedulerFactory, StdSchedulerFactory>();
3. api中依赖注入
private readonly ISchedulerFactory _schedulerFactory;
private readonly IScheduler _scheduler;
public ValuesController( ISchedulerFactory schedulerFactory)
{
_schedulerFactory = schedulerFactory;
_scheduler = _schedulerFactory.GetScheduler().Result; //通过工场类获得调度器
}
简单使用
public async Task<IActionResult> RecurringJob()
{
//开启调度器
await _scheduler.Start();
//创建触发器(也叫时间策略)
var trigger = TriggerBuilder.Create()
// .WithSimpleSchedule(x => x.WithIntervalInMinutes(1).RepeatForever())//每分钟执行一次,一直重复执行
//.WithSimpleSchedule(x => x.WithIntervalInSeconds(2).WithRepeatCount(5))//每2秒执行一次,重复执行五次
.WithCronSchedule("0/2 * * * * ?") //使用cron指定运行时间来执行,每2秒运行一次
// .WithIdentity("fcbjob","fcbgroup")
.Build();
//创建作业实例
//Jobs即我们需要执行的作业
var jobDetail = JobBuilder.Create<FCBJob>()
.WithIdentity("Myjob", "fcbgroup")//我们给这个作业取了个“Myjob”的名字,取了个组名为“fcbgroup”,这里会通过这两个名字来生成唯一的jobkey,如果不指定会默认生成一个唯一jobkey
.Build();
await _scheduler.ScheduleJob(jobDetail, trigger);
return Ok("执行成功");
}
一个Job执行多个触发器
job和trigger 可以是一对多的关系
public async Task<IActionResult> RecurringJobs()
{
//开启调度器
await _scheduler.Start();
//创建触发器(也叫时间策略)
var trigger = TriggerBuilder.Create()
.WithCronSchedule("0/2 * * * * ?") //使用cron指定运行时间来执行,每2秒运行一次
.WithIdentity("fcbjob","fcbgroup")
.Build();
var trigger2 = TriggerBuilder.Create()
.WithCronSchedule("0/1 * * * * ?") //使用cron指定运行时间来执行,每2秒运行一次
.WithIdentity("fcbjob2", "fcbgroup")
.Build();
var jobDetail2 = JobBuilder.Create<FCBJob2>()
.WithIdentity("Myjob2", "fcbgroup")
.Build();
Dictionary<IJobDetail, IReadOnlyCollection<ITrigger>> keyValuePairs = new Dictionary<IJobDetail, IReadOnlyCollection<ITrigger>>();
keyValuePairs.Add(jobDetail2, new List<ITrigger>() {
trigger,trigger2
});
await _scheduler.ScheduleJobs(keyValuePairs,true);
return Ok("执行成功");
}
停止任务调度
public async Task<IActionResult> ShutdownScheduler()
{
await _scheduler.Shutdown();
return Ok();
}
暂停定时任务
public async Task<IActionResult> PauseJob()
{
//暂停job
//JobKey jobKey = new JobKey("Myjob", "fcbgroup");
//if (await _scheduler.CheckExists(jobKey))
//{
// await _scheduler.PauseJob(jobKey);
//}
//暂停triggerKey
TriggerKey triggerKey = new TriggerKey("fcbjob", "fcbgroup");
if (await _scheduler.CheckExists(triggerKey))
{
await _scheduler.PauseTrigger(triggerKey);
}
return Ok();
}
恢复定时任务
public async Task<IActionResult> ResumeJob()
{
//恢复job
//JobKey jobKey = new JobKey("Myjob", "fcbgroup");
//if (await _scheduler.CheckExists(jobKey))
//{
// await _scheduler.ResumeJob(jobKey);
//}
//恢复triggerKey
TriggerKey triggerKey = new TriggerKey("fcbjob", "fcbgroup");
if (await _scheduler.CheckExists(triggerKey))
{
await _scheduler.ResumeTrigger(triggerKey);
}
return Ok();
}
删除定时任务
public async Task<IActionResult> DeleteJob()
{
JobKey jobKey = new JobKey("Myjob", "fcbgroup");
if (await _scheduler.CheckExists(jobKey))
{
await _scheduler.DeleteJob(jobKey);
}
return Ok();
}