想必大家在工作中经常会遇到这样类似的需求,在某个时间或者需要不间断的执行某个业务动作去满足任务需求。例如,我们写了一个job,定时去处理一些任务,在没有了解到Quartz.Net之前,我是这样做的,进行轮询处理,如图:

Quartz.Net初探-LMLPHP

是不是感觉很low啊。前些日子,了解到了Quartz.Net,它是一个强大的开源任务调度器,它提供的触发器以及Cron表达式能够很好的满足我们在日常开发中遇到的定时服务的工作处理,为了在以后工作中更好的使用它,我对它的基本使用方法进行了整理,当然下面所讲到的只是它的一些常用功能,至于更强大的功能,例如远程调度等等,还需要后续再进一步了解。但是在我看来,已能够满足我们在日常中的大部分开发工作。

1、建立如下解决方案,如图

Quartz.Net初探-LMLPHP

正如大家看到的,我在解决方案中添加了QuartzTest的控制台项目进行demo演示,需要说明的是,大家可通过Nuget将Quartz包添加至项目当中。根据Quartz的常用操作,整理出了 BaseJob以及QuartzHelper帮助类。

BaseJob类中包含了要执行任务的基本信息,例如Job名称,组名,触发器名称,执行间隔时间等等信息,在实现具体Job时,只要继承该基类并使用相应的构造函数对Job基本信息进行初始化即可。

如下图:

Quartz.Net初探-LMLPHP

QuartzHelper中对常用的任务调度方法进行了整理,这里我们将TestJob添加至调度器并开始任务的执行,如下图:

Quartz.Net初探-LMLPHP

该Demo以及整理的完整代码如下:

  /// <summary>
/// 任务基类
/// </summary>
public abstract class BaseJob : IJob
{
private string _jobName = string.Empty;
private string _gropName = string.Empty;
private string _triggerName = string.Empty;
private int _intervalTime;
private DateTimeOffset _startTime;
private DateTimeOffset? _endTime;
private int _repeatCount;
private string _cronExpression; /// <summary>
/// 无参构造函数
/// </summary>
public BaseJob()
{ } /// <summary>
/// 构造函数
/// </summary>
/// <param name="jobName">任务名称</param>
/// <param name="triggerName">触发器名称</param>
/// <param name="gropName">任务组名称</param>
/// <param name="intervalTime">间隔时间</param>
public BaseJob(string jobName, string triggerName, string gropName, int intervalTime)
{
this._jobName = jobName;
this._triggerName = triggerName;
this._gropName = gropName;
this._intervalTime = intervalTime;
} /// <summary>
/// 构造函数
/// </summary>
/// <param name="jobName">任务名称</param>
/// <param name="triggerName">触发器名称</param>
/// <param name="gropName">任务组名称</param>
/// <param name="intervalTime">间隔时间</param>
/// <param name="cronExpression">cron表达式</param>
public BaseJob(string jobName, string triggerName, string gropName, int intervalTime, string cronExpression)
{
this._jobName = jobName;
this._triggerName = triggerName;
this._gropName = gropName;
this._intervalTime = intervalTime;
this._cronExpression = cronExpression;
} /// <summary>
/// 构造函数
/// </summary>
/// <param name="jobName">任务名称</param>
/// <param name="triggerName">触发器名称</param>
/// <param name="gropName">任务组名称</param>
/// <param name="intervalTime">间隔时间</param>
/// <param name="startTime">开始时间</param>
/// <param name="endTime">结束时间</param>
public BaseJob(string jobName, string triggerName, string gropName, int intervalTime, DateTimeOffset startTime, DateTimeOffset? endTime)
{
this._jobName = jobName;
this._triggerName = triggerName;
this._gropName = gropName;
this._intervalTime = intervalTime;
this._startTime = startTime;
this._endTime = endTime;
} /// <summary>
/// 构造函数
/// </summary>
/// <param name="jobName">任务名称</param>
/// <param name="triggerName">触发器名称</param>
/// <param name="gropName">任务组名称</param>
/// <param name="intervalTime">间隔时间</param>
/// <param name="startTime">开始时间</param>
/// <param name="endTime">结束时间</param>
/// <param name="repeatCount">重复次数</param>
public BaseJob(string jobName, string triggerName, string gropName, int intervalTime, DateTimeOffset startTime, DateTimeOffset? endTime, int repeatCount)
{
this._jobName = jobName;
this._triggerName = triggerName;
this._gropName = gropName;
this._intervalTime = intervalTime;
this._startTime = startTime;
this._endTime = endTime;
this._repeatCount = repeatCount;
} /// <summary>
/// 任务名称
/// </summary>
public string JobName
{
get { return _jobName; }
set { _jobName = value; }
} /// <summary>
/// 触发器名称
/// </summary>
public string TriggerName
{
get { return _triggerName; }
set { _triggerName = value; }
} /// <summary>
/// 任务组名称
/// </summary>
public string GropName
{
get { return _gropName; }
set { _gropName = value; }
} /// <summary>
/// 执行间隔时间
/// </summary>
public int IntervalTime
{
get { return _intervalTime; }
set { _intervalTime = value; }
} /// <summary>
/// 开始时间
/// </summary>
public DateTimeOffset StartTime
{
get { return _startTime; }
set
{
if (value == null || value == DateTime.MinValue) _startTime = SystemTime.UtcNow();
else _startTime = value;
}
} /// <summary>
/// 结束时间
/// </summary>
public DateTimeOffset? EndTime
{
get { return _endTime; }
set { _endTime = value; }
} /// <summary>
/// 重复执行次数
/// </summary>
public int RepeatCount
{
get { return _repeatCount; }
set { _repeatCount = value; }
} /// <summary>
/// Cron表达式
/// </summary>
public string CronExpression
{
get { return _cronExpression; }
set { _cronExpression = value; }
} /// <summary>
/// 任务执行
/// </summary>
/// <param name="context">任务执行上下文</param>
public abstract void Execute(IJobExecutionContext context);
}
  /// <summary>
/// Quartz帮助类
/// </summary>
public class QuartzHelper
{
private static ISchedulerFactory _schedulerFactory;
private static IScheduler _scheduler; /// <summary>
/// 构造函数
/// </summary>
static QuartzHelper()
{
_schedulerFactory = CreateSchedulerFactory();
_scheduler = GetScheduler();
} #region 获取服务器使用的调度程序
/// <summary>
/// 获取服务器使用的调度程序。
/// </summary>
/// <returns></returns>
protected static IScheduler GetScheduler()
{
return _schedulerFactory.GetScheduler();
}
#endregion #region 创建调度器工厂
/// <summary>
/// 创建调度器工厂。
/// </summary>
/// <returns></returns>
protected static ISchedulerFactory CreateSchedulerFactory()
{
return new StdSchedulerFactory();
}
#endregion #region 委托调度器,启动实例
/// <summary>
/// 委托调度器,启动实例。
/// </summary>
public static void Start()
{
try
{
_scheduler.Start();
}
catch (Exception ex)
{
throw ex;
}
}
#endregion #region 委托调度器,停止实例
/// <summary>
/// 委托调度器,停止实例。
/// </summary>
public static void Stop()
{
try
{
if (!_scheduler.IsShutdown)
_scheduler.Shutdown(true);
}
catch (Exception ex)
{
throw ex;
}
}
#endregion #region 暂停调度器中所有的活动
/// <summary>
/// 暂停调度器中所有的活动。
/// </summary>
public static void Pause()
{
try
{
_scheduler.PauseAll();
}
catch (Exception ex)
{
throw ex;
}
}
#endregion #region 恢复所有活动
/// <summary>
/// 恢复所有活动。
/// </summary>
public static void Resume()
{
try
{
_scheduler.ResumeAll();
}
catch (Exception ex)
{
throw ex;
}
}
#endregion #region 添加任务(任务间隔时间单位:小时)
/// <summary>
/// 添加任务(任务间隔时间单位:小时)
/// </summary>
/// <typeparam name="T">具体任务</typeparam>
public static void AddJobForHours<T>()
where T : BaseJob, new()
{
try
{
T job = new T();
IJobDetail jobDetail = JobBuilder.Create<T>().WithIdentity(job.JobName, job.GropName).Build();
ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().WithIdentity(job.TriggerName, job.GropName).StartNow()
.WithSimpleSchedule(x => x.WithIntervalInHours(job.IntervalTime).RepeatForever())
.Build();
_scheduler.ScheduleJob(jobDetail, trigger);
}
catch (Exception ex)
{
throw ex;
}
}
#endregion #region 添加任务(任务间隔时间单位:分钟)
/// <summary>
/// 添加任务(任务间隔时间单位:分钟)
/// </summary>
/// <typeparam name="T">具体任务</typeparam>
public static void AddJobForMinutes<T>()
where T : BaseJob, new()
{
try
{
T job = new T();
IJobDetail jobDetail = JobBuilder.Create<T>().WithIdentity(job.JobName, job.GropName).Build();
ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().WithIdentity(job.TriggerName, job.GropName).StartNow()
.WithSimpleSchedule(x => x.WithIntervalInMinutes(job.IntervalTime).RepeatForever())
.Build();
_scheduler.ScheduleJob(jobDetail, trigger);
}
catch (Exception ex)
{
throw ex;
}
}
#endregion #region 添加任务(任务间隔时间单位:秒)
/// <summary>
/// 添加任务(任务间隔时间单位:秒)
/// </summary>
/// <typeparam name="T">具体任务</typeparam>
public static void AddJobForSeconds<T>()
where T : BaseJob, new()
{
try
{
T job = new T();
IJobDetail jobDetail = JobBuilder.Create<T>().WithIdentity(job.JobName, job.GropName).Build();
ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().WithIdentity(job.TriggerName, job.GropName).StartNow()
.WithSimpleSchedule(x => x.WithIntervalInSeconds(job.IntervalTime).RepeatForever())
.Build();
_scheduler.ScheduleJob(jobDetail, trigger);
}
catch (Exception ex)
{
throw ex;
}
}
#endregion #region 根据开始以及结束时间进行添加任务(任务间隔时间单位:小时)
/// <summary>
/// 根据开始以及结束时间进行添加任务(任务间隔时间单位:小时)
/// </summary>
/// <typeparam name="T">具体任务</typeparam>
public static void AddJobForHoursStartEndTime<T>()
where T : BaseJob, new()
{
try
{
T job = new T();
IJobDetail jobDetail = JobBuilder.Create<T>().WithIdentity(job.JobName, job.GropName).Build();
ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().WithIdentity(job.TriggerName, job.GropName).StartAt(job.StartTime).EndAt(job.EndTime)
.WithSimpleSchedule(x => x.WithIntervalInHours(job.IntervalTime).RepeatForever())
.Build();
_scheduler.ScheduleJob(jobDetail, trigger);
}
catch (Exception ex)
{
throw ex;
}
}
#endregion #region 根据开始以及结束时间进行添加任务(任务间隔时间单位:分钟)
/// <summary>
/// 根据开始以及结束时间进行添加任务(任务间隔时间单位:分钟)
/// </summary>
/// <typeparam name="T">具体任务</typeparam>
public static void AddJobForMinutesStartEndTime<T>()
where T : BaseJob, new()
{
try
{
T job = new T();
IJobDetail jobDetail = JobBuilder.Create<T>().WithIdentity(job.JobName, job.GropName).Build();
ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().WithIdentity(job.TriggerName, job.GropName).StartAt(job.StartTime).EndAt(job.EndTime)
.WithSimpleSchedule(x => x.WithIntervalInMinutes(job.IntervalTime).RepeatForever())
.Build();
_scheduler.ScheduleJob(jobDetail, trigger);
}
catch (Exception ex)
{
throw ex;
}
}
#endregion #region 根据开始以及结束时间进行添加任务(任务间隔时间单位:秒)
/// <summary>
/// 根据开始以及结束时间添加任务(任务间隔时间单位:秒)
/// </summary>
/// <typeparam name="T">具体任务</typeparam>
public static void AddJobForSecondsStartEndTime<T>()
where T : BaseJob, new()
{
try
{
T job = new T();
IJobDetail jobDetail = JobBuilder.Create<T>().WithIdentity(job.JobName, job.GropName).Build();
ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().WithIdentity(job.TriggerName, job.GropName).StartAt(job.StartTime).EndAt(job.EndTime)
.WithSimpleSchedule(x => x.WithIntervalInSeconds(job.IntervalTime).RepeatForever())
.Build();
_scheduler.ScheduleJob(jobDetail, trigger);
}
catch (Exception ex)
{
throw ex;
}
}
#endregion #region 根据开始以及结束时间执行指定重复次数进行添加任务(任务间隔时间单位:小时)
/// <summary>
/// 根据开始以及结束时间执行指定重复次数进行添加任务(任务间隔时间单位:小时)
/// </summary>
/// <typeparam name="T">具体任务</typeparam>
public static void AddJobForHoursRepeatCount<T>()
where T : BaseJob, new()
{
try
{
T job = new T();
IJobDetail jobDetail = JobBuilder.Create<T>().WithIdentity(job.JobName, job.GropName).Build();
ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().WithIdentity(job.TriggerName, job.GropName).StartAt(job.StartTime).EndAt(job.EndTime)
.WithSimpleSchedule(x => x.WithIntervalInHours(job.IntervalTime).WithRepeatCount(job.RepeatCount))
.Build();
_scheduler.ScheduleJob(jobDetail, trigger);
}
catch (Exception ex)
{
throw ex;
}
}
#endregion #region 根据开始以及结束时间执行指定重复次数进行添加任务(任务间隔时间单位:分钟)
/// <summary>
/// 根据开始以及结束时间执行指定重复次数进行添加任务(任务间隔时间单位:分钟)
/// </summary>
/// <typeparam name="T">具体任务</typeparam>
public static void AddJobForMinutesRepeatCount<T>()
where T : BaseJob, new()
{
try
{
T job = new T();
IJobDetail jobDetail = JobBuilder.Create<T>().WithIdentity(job.JobName, job.GropName).Build();
ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().WithIdentity(job.TriggerName, job.GropName).StartAt(job.StartTime).EndAt(job.EndTime)
.WithSimpleSchedule(x => x.WithIntervalInMinutes(job.IntervalTime).WithRepeatCount(job.RepeatCount))
.Build();
_scheduler.ScheduleJob(jobDetail, trigger);
}
catch (Exception ex)
{
throw ex;
}
}
#endregion #region 根据开始以及结束时间执行指定重复次数进行添加任务(任务间隔时间单位:秒)
/// <summary>
/// 根据开始以及结束时间执行指定重复次数进行添加任务(任务间隔时间单位:秒)
/// </summary>
/// <typeparam name="T">具体任务</typeparam>
public static void AddJobForSecondsRepeatCount<T>()
where T : BaseJob, new()
{
try
{
T job = new T();
IJobDetail jobDetail = JobBuilder.Create<T>().WithIdentity(job.JobName, job.GropName).Build();
ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().WithIdentity(job.TriggerName, job.GropName).StartAt(job.StartTime).EndAt(job.EndTime)
.WithSimpleSchedule(x => x.WithIntervalInSeconds(job.IntervalTime).WithRepeatCount(job.RepeatCount))
.Build();
_scheduler.ScheduleJob(jobDetail, trigger);
}
catch (Exception ex)
{
throw ex;
}
}
#endregion #region 通过Cron表达式添加任务
/// <summary>
/// 通过Cron表达式添加任务
/// </summary>
/// <typeparam name="T">具体任务</typeparam>
public static void AddJobForCron<T>()
where T : BaseJob, new()
{
try
{
T job = new T();
IJobDetail jobDetail = JobBuilder.Create<T>().WithIdentity(job.JobName, job.GropName).Build(); ICronTrigger trigger = (ICronTrigger)TriggerBuilder.Create()
.WithIdentity(job.TriggerName, job.GropName)
.WithCronSchedule(job.CronExpression)
.Build();
_scheduler.ScheduleJob(jobDetail, trigger);
}
catch (Exception ex)
{
throw ex;
}
}
#endregion
}
   /// <summary>
/// 测试 job
/// </summary>
public class TestJob : BaseJob
{
public TestJob() : base("TestJob", "TestTrigger", "TestGrop",) { }
public override void Execute(IJobExecutionContext context)
{
try
{
Console.WriteLine(string.Format("当前任务执行时间:{0}", DateTime.Now.ToString()));
Thread.Sleep(TimeSpan.FromSeconds());
}
catch (Exception ex)
{
throw ex;
}
}
}
  class Program
{
static void Main(string[] args)
{
QuartzHelper.AddJobForSeconds<TestJob>();
QuartzHelper.Start();
}
}

2、运行解决方案,得到如下结果

Quartz.Net初探-LMLPHP

发现是不是任务按照我们所希望的那样运行了,但是大家有没有注意到,TestJob中 有这样一句代码:  Thread.Sleep(TimeSpan.FromSeconds(3));

任务是Sleep3秒钟的,可是我们的Job却一直在执行呢,即使上一次任务还没执行完,它又开始执行了。在我们的实际开发中,我们需要一次任务执行完成后再执行下一次任务。
我们对TestJob 进行改造,代码如下:
   /// <summary>
/// 测试 job
/// </summary>
[DisallowConcurrentExecution]
public class TestJob : BaseJob
{
public TestJob() : base("TestJob", "TestTrigger", "TestGrop",) { }
public override void Execute(IJobExecutionContext context)
{
try
{
Console.WriteLine(string.Format("当前任务执行时间:{0}", DateTime.Now.ToString()));
Thread.Sleep(TimeSpan.FromSeconds());
}
catch (Exception ex)
{
throw ex;
}
}
}

再次运行,如图:

Quartz.Net初探-LMLPHP

大家发现区别没呢,没错,我们在TestJob类上添加了“DisallowConcurrentExecution”特性,这样,就能在一次任务执行完成后,再进行下次任务的执行了。

05-11 22:47