1.NuGet添加包引用
点击安装。
2.建立Job任务程序
using Quartz;
using System.Threading.Tasks;
namespace Practice.Jobs
{
//DisallowConcurrentExecution能保证上一个周期的任务还没执行完之前,下一个周期到来了就会被忽略
[DisallowConcurrentExecution]
public class WeatherJob : IJob
{
public Task Execute(IJobExecutionContext context)
{
return Task.Run(() =>
{
Init();
});
}
private void Init()
{
//具体逻辑
}
}
}
3.新建Job监听程序
using Quartz;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Practice.Jobs
{
public class WeatherJobListener : IJobListener
{
/// <summary>
/// 返回一个字符串用以说明 JobListener 的名称。
/// 对于注册为全局的监听器,getName()主要用于记录日志,对于由特定 Job 引用的JobListener,
/// 注册在 JobDetail 上的监听器名称必须匹配从监听器getName() 方法的返回值。
/// </summary>
public string Name => "WeatherJobListener";
/// <summary>
/// Scheduler 在 JobDetail 将要被执行时调用这个方法。
/// </summary>
/// <param name="context"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default)
{
//Task.Run(() => { Console.WriteLine($"Job: {context.JobDetail.Key} 即将被执行..."); }, cancellationToken);
//Job即将执行
return Task.Factory.StartNew(() =>
{
Console.WriteLine($"Job: {context.JobDetail.Key} 即将被执行...");
}, cancellationToken);
}
/// <summary>
/// Scheduler 在 JobDetail 即将被执行,但又被 TriggerListener否决了时调用这个方法。
/// </summary>
/// <param name="context"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default)
{
//Task.Run(() => { Console.WriteLine($"Job: {context.JobDetail.Key} 被忽略..."); }, cancellationToken);
return Task.Factory.StartNew(() => {
Console.WriteLine($"Job: {context.JobDetail.Key} 被忽略...");
}, cancellationToken);
}
/// <summary>
/// Scheduler 在 JobDetail 被执行之后调用这个方法。
/// </summary>
/// <param name="context"></param>
/// <param name="jobException"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default)
{
//Task.Run(() => { Console.WriteLine($"Job: {context.JobDetail.Key} 已经被执行完毕..."); }, cancellationToken);
//Job执行完成
return Task.Factory.StartNew(() =>
{
Console.WriteLine($"Job: {context.JobDetail.Key} 已经被执行完毕...");
}, cancellationToken);
}
}
}
4.新建Trigger监听程序
using Quartz;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Practice.Jobs
{
public class WeatherTriggerListener : ITriggerListener
{
/// <summary>
/// TriggerListner 接口的 getName()返回一个字符串用以说明监听器的名称。
/// 对于非全局的 TriggerListener,在 addTriggerListener()方法中给定的名称必须与监听器的 getName() 方法返回值相匹配。
/// </summary>
public string Name => "WeatherTriggerListener";
/// <summary>
/// (1) Trigger被激发 它关联的job即将被运行
///
/// 当与监听器相关联的 Trigger 被触发,Job 上的 execute()方法将要被执行时,Scheduler 就调用这个方法。
/// 在全局 TriggerListener 情况下,这个方法为所有 Trigger被调用。
/// </summary>
/// <param name="trigger"></param>
/// <param name="context"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public Task TriggerFired(ITrigger trigger, IJobExecutionContext context, CancellationToken cancellationToken = default)
{
return Task.Run(() => { Console.WriteLine($"Trigger: {trigger.Key} 触发..."); }, cancellationToken);
}
/// <summary>
/// (2) Trigger被激发 它关联的job即将被运行,先执行(1),在执行(2) 如果返回TRUE 那么任务job会被终止
/// 在 Trigger 触发后,Job 将要被执行时由 Scheduler调用这个方法。
/// TriggerListener 给了一个选择去否决 Job 的执行。
/// 假如这个方法返回 true,这个 Job 将不会为此次Trigger 触发而得到执行。
/// </summary>
/// <param name="trigger"></param>
/// <param name="context"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public Task<bool> VetoJobExecution(ITrigger trigger, IJobExecutionContext context, CancellationToken cancellationToken = default)
{
return Task.FromResult(true);
}
/// <summary>
/// (3) 当Trigger错过被激发时执行,比如当前时间有很多触发器都需要执行,
/// 但是线程池中的有效线程都在工作,那么有的触发器就有可能超时,错过这一轮的触发。
///
/// Scheduler 调用这个方法是在 Trigger 错过触发时。
/// 如这个方法的 JavaDoc所指出的,你应该关注此方法中持续时间长的逻辑:在出现许多错过触发的 Trigger 时,长逻辑会导致骨牌效应。
/// 你应当保持这上方法尽量的小。
/// </summary>
/// <param name="trigger"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public Task TriggerMisfired(ITrigger trigger, CancellationToken cancellationToken = default)
{
return Task.Run(() => { Console.WriteLine($"Trigger: {trigger.Key} 错过触发..."); }, cancellationToken);
}
/// <summary>
/// (4) 任务完成时触发
///
/// Trigger 被触发并且完成了 Job 的执行时,Scheduler 调用这个方法。
/// 这不是说这个Trigger 将不再触发了,而仅仅是当前 Trigger 的触发(并且紧接着的 Job 执行) 结束时。
/// 这个 Trigger也许还要在将来触发多次的。
/// </summary>
/// <param name="trigger"></param>
/// <param name="context"></param>
/// <param name="triggerInstructionCode"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default)
{
return Task.Run(() => { Console.WriteLine($"Trigger: {trigger.Key} 完成..."); }, cancellationToken);
}
}
}
5.主程序调用并启动Job任务
using Practice.Jobs;
using Quartz;
using Quartz.Impl;
using System;
using System.Threading.Tasks;
namespace Practice
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
Init().GetAwaiter().GetResult();
Console.ReadKey();
}
public static async Task Init()
{
//建立具体执行的任务Job
IJobDetail jobDetail = JobBuilder.Create<WeatherJob>()
.WithIdentity("weatherJob", "weatherJobGrop")
.WithDescription("定时获取天气信息")
.Build();
//制定时间策略
ITrigger weatherTrigger = TriggerBuilder.Create()
.WithIdentity("weatherTrigger", "weatherJobGrop")
.WithDescription("定时获取天气信息")
.WithCronSchedule("0 0/10 * * * ?")
.Build();
StdSchedulerFactory stdSchedulerFactory = new();
IScheduler scheduler=await stdSchedulerFactory.GetScheduler();
//把策略和任务放入到Scheduler
await scheduler.ScheduleJob(jobDetail, weatherTrigger);
//Job监听
scheduler.ListenerManager.AddJobListener(new WeatherJobListener());
//Trigger监听
scheduler.ListenerManager.AddTriggerListener(new WeatherTriggerListener());
await scheduler.Start();
}
}
}