Quartz.NET 入门
概述
Quartz.NET是一个开源的作业调度框架,非常适合在平时的工作中,定时轮询数据库同步,定时邮件通知,定时处理数据等。 Quartz.NET允许开发人员根据时间间隔(或天)来调度作业。它实现了作业和触发器的多对多关系,还能把多个作业与不同的触发器关联。
整合了 Quartz.NET的应用程序可以重用来自不同事件的作业,还可以为一个事件组合多个作业。
快速搭建一个Quartz
第一步:安装
Install-Package Quartz
Install-Package Common.Logging.Log4Net1211
Install-Package log4net
Install-Package Topshelf
Install-Package Topshelf.Log4Net
Quartz依赖Common.Logging和Common.Logging.Log4Net1211,又因为Log4Net是比较标准的日志工具,因此我们一般都会安装log4net,
另外定时作业一般都允许在后台服务中,因此我们也安装了Topshelf。
第二步:实现IJob
TestJob.cs 实现IJob,在Execute方法里编写要处理的业务逻辑,系统就会按照Quartz的配置,定时处理。
using log4net;
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace QuartzDemo.QuartzJobs
{
public sealed class TestJob : IJob
{
private readonly ILog _logger = LogManager.GetLogger(typeof(TestJob));
public void Execute(IJobExecutionContext context)
{
_logger.InfoFormat("TestJob测试");
}
}
}
第三步:使用Topshelf调度任务
using Quartz;
using Quartz.Impl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Topshelf;
namespace QuartzDemo
{
public sealed class ServiceRunner : ServiceControl, ServiceSuspend
{
private readonly IScheduler scheduler;
public ServiceRunner()
{
scheduler = StdSchedulerFactory.GetDefaultScheduler();
}
public bool Start(HostControl hostControl)
{
scheduler.Start();
return true;
}
public bool Stop(HostControl hostControl)
{
scheduler.Shutdown(false);
return true;
}
public bool Continue(HostControl hostControl)
{
scheduler.ResumeAll();
return true;
}
public bool Pause(HostControl hostControl)
{
scheduler.PauseAll();
return true;
}
}
}
第四步:程序入口
namespace QuartzDemo
{
class Program
{
static void Main(string[] args)
{
log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(AppDomain.CurrentDomain.BaseDirectory + "log4net.config"));
HostFactory.Run(x =>
{
x.UseLog4Net();
x.Service();
x.SetDescription("QuartzDemo服务描述");
x.SetDisplayName("QuartzDemo服务显示名称");
x.SetServiceName("QuartzDemo服务名称");
x.EnablePauseAndContinue();
});
}
}
}
第五步:配置quartz.config、quartz_jobs.xml、log4net.config
quartz.config
因格式原因在#前加了/,使用时去掉即可
/# You can configure your scheduler in either configuration section
/# or in quartz properties file
/# Configuration section has precedence
quartz.scheduler.instanceName = QuartzTest
/# configure thread pool info
quartz.threadPool.type = Quartz.Simpl.SimpleThreadPool, Quartz
quartz.threadPool.threadCount = 10
quartz.threadPool.threadPriority = Normal
/# job initialization plugin handles our xml reading, without it defaults are used
quartz.plugin.xml.type = Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz
quartz.plugin.xml.fileNames = ~/quartz_jobs.xml
/# export this server to remoting context
/#quartz.scheduler.exporter.type = Quartz.Simpl.RemotingSchedulerExporter, Quartz
/#quartz.scheduler.exporter.port = 555
/#quartz.scheduler.exporter.bindName = QuartzScheduler
/#quartz.scheduler.exporter.channelType = tcp
/#quartz.scheduler.exporter.channelName = httpQuartz
quartz_jobs.xml
true
SimpleJob
sampleGroup
Sample job for Quartz Server
WindowsService.Job.SimpleJob, WindowsService
true
false
JobTrigger
JobTriggers
cron trigger
SimpleJob
sampleGroup
0/2 * * * * ?
job 任务:用来定义每个具体的任务的,多个任务请创建多个job节点即可
+ name(必填) 任务名称,同一个group中多个job的name不能相同,若未设置group则所有未设置group的job为同一个分组
+ group(选填) 任务所属分组,用于标识任务所属分组
+ description(选填) 任务描述,用于描述任务具体内容
+ job-type(必填) 任务类型,任务的具体类型及所属程序集,格式:实现了IJob接口的包含完整命名空间的类名,程序集名称
+ durable(选填) 具体作用不知,官方示例中默认为true
+ recover(选填) 具体作用不知,官方示例中默认为false
trigger 任务触发器:用于定义使用何种方式出发任务(job),同一个job可以定义多个trigger ,多个trigger 各自独立的执行调度,
每个trigger 中必须且只能定义一种触发器类型(calendar-interval、simple、cron)
+ simple 简单任务的触发器类型,可以调度用于重复执行的任务
* name(必填) 触发器名称,同一个分组中的名称必须不同
* group(选填) 触发器组
* description(选填) 触发器描述
* job-name(必填) 要调度的任务名称,该job-name必须和对应job节点中的name完全相同
* job-group(选填) 调度任务(job)所属分组,该值必须和job中的group完全相同
* start-time(选填) 任务开始执行时间utc时间,北京时间需要+08:00,
如:2012-04-01T08:00:00+08:00 表示北京时间2012年4月1日上午8:00开始执行,
注意服务启动或重启时都会检测此属性,若没有设置此属性或者start-time设置的时间比当前时间较早,
则服务启动后会立即执行一次调度,若设置的时间比当前时间晚,服务会等到设置时间相同后才会第一次执行任务,一般若无特殊需要请不要设置此属性
* repeat-count(必填) 任务执行次数,如:-1 表示无限次执行,10 表示执行10次
* repeat-interval(必填) 任务触发间隔(毫秒),如:10000 每10秒执行一次
+ cron:复杂任务触发器--使用cron表达式定制任务调度
* name(必填) 触发器名称,同一个分组中的名称必须不同
* group(选填) 触发器组
* escription(选填) 触发器描述
* job-name(必填) 要调度的任务名称,该job-name必须和对应job节点中的name完全相同
* job-group(选填) 调度任务(job)所属分组,该值必须和job中的group完全相同
* start-time(选填) 任务开始执行时间utc时间,北京时间需要+08:00,
如:2012-04-01T08:00:00+08:00 表示北京时间2012年4月1日上午8:00开始执行,
注意服务启动或重启时都会检测此属性,若没有设置此属性,服务会根据cron-expression的设置执行任务调度;若start-time设置的时间比当前时间较早,则服务启动后会忽略掉cron-expression设置,立即执行一次调度,之后再根据cron-expression执行任务调度;若设置的时间比当前时间晚,则服务会在到达设置时间相同后才会应用cron-expression,
根据规则执行任务调度,一般若无特殊需要请不要设置此属性
* cron-expression(必填) cron表达式,如:0/10 * * * * ? 每10秒执行一次
log4net.config
Quartz任务调度
泛型数组批量job(可用数据库)+服务日志+log4net打印日志+制作windows服务
安装
Install-Package Quartz(2.6.2)
Install-Package Common.Logging.Log4Net1211(3.0)
Install-Package Topshelf(3.2)
Install-Package Topshelf.Log4Net(3.2)
配置文件
相关Job类
JobInfo对象(任务信息),JobType类型
任务信息:名称、触发器、群组、类型(根据不同的类型执行不同的Job内容
public class JobInfo
{
public JobInfo(string jobName, string group, string trigger, JobType jobType)
{
if (jobName == null || trigger == null || group == null)
{
throw new ArgumentNullException("jobName");
}
this.JobName = jobName;
this.Trigger = trigger;
this.Group = group;
this.JobType = jobType;
}
///
/// 名称
///
public string JobName { get; set; }
///
/// Job的触发器 cron表达式
///
public string Trigger { get; set; }
///
/// 群组
///
public string Group { get; set; }
///
/// Job类型
///
public JobType JobType { get; set; }
}
///
/// Job类型枚举
///
public enum JobType
{
///
/// 任务1
///
Job1 = 1,
///
/// 任务2
///
Job2 = 2
}
JobInfoList任务集合
模拟的任务集合,实际应用中可固定,可从数据库中获取
public class JobInfoList
{
///
/// 脚本服务组
///
public static List JobList_ZhongShanHos = new List
{
new JobInfo("任务1", "测试脚本", "*/5 * * * * ?", JobType.Job1),
new JobInfo("任务2", "测试脚本", "*/7 * * * * ?", JobType.Job2)
};
}
Job内容
配置具体的Job内容与需要输出的自定义日志,这里的日志使用log4net作为记录
using System;
using Quartz;
namespace T5.Jobs
{
public class TestJob : IJob
{
private static readonly log4net.ILog LogInfo = log4net.LogManager.GetLogger("LogCustomEx");
private static readonly log4net.ILog LogError = log4net.LogManager.GetLogger("LogError");
public void Execute(IJobExecutionContext context)
{
var map = context.JobDetail.JobDataMap;
var jobInfo = map["KEY"] as JobInfo;
if (jobInfo == null) { return; }
//记录日志
LogInfo.Info("\n【服务已启动】" + "\n【启动组】:" + jobInfo.Group + "\n【启动名称】:" + jobInfo.JobName + "\n【启动时间】:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
try
{
switch (jobInfo.JobType)
{
//基础信息
case JobType.Job1: LogInfo.Info("这是任务1"); break;
case JobType.Job2: LogInfo.Info("这是任务2"); break;
default: break;
}
}
catch (Exception ex)
{
//记录日志
LogError.Error("\n【服务执行出错】" +
"\n【启动组】:" + jobInfo.Group +
"\n【启动名称】:" + jobInfo.JobName +
"\n【时间】:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") +
"\n【错误信息】:" + ex.Message);
return;
}
}
}
}
配置Job执行方法
using System.Collections.Generic;
using Quartz;
using Quartz.Impl;
using T5.Jobs;
using Topshelf;
namespace T5
{
public sealed class ServerRunner : ServiceControl, ServiceSuspend
{
private readonly IScheduler scheduler;
public ServerRunner()
{
scheduler = StdSchedulerFactory.GetDefaultScheduler();
}
public bool Start(HostControl hostControl)
{
var jobList = new List();
//配置JobList任务
jobList.AddRange(JobInfoList.JobList_ZhongShanHos);
jobList.ForEach(
x =>
{
var dic = new Dictionary { { "KEY", x } };
var map = new JobDataMap(dic);
var job =
JobBuilder.Create()
.WithIdentity(x.JobName, x.Group)
.UsingJobData(map)
.RequestRecovery()
.Build();
var trigger =
TriggerBuilder.Create()
.WithIdentity(x.JobName, x.Group)
.WithCronSchedule(x.Trigger)
.Build();
scheduler.ScheduleJob(job, trigger);
});
scheduler.Start();
return true;
}
public bool Stop(HostControl hostControl)
{
scheduler.Shutdown(false);
return true;
}
public bool Continue(HostControl hostControl)
{
scheduler.ResumeAll();
return true;
}
public bool Pause(HostControl hostControl)
{
scheduler.PauseAll();
return true;
}
}
}
配置入口文件
using Topshelf;
namespace T5
{
class Program
{
static void Main(string[] args)
{
//配置Log4日志
log4net.Config.XmlConfigurator.Configure();
//Windows服务
HostFactory.Run(x =>
{
x.UseLog4Net();
x.Service();
x.SetDescription("Quartz日志记录服务");
x.SetDisplayName("Quartz");
x.SetServiceName("QuartzLog");
x.EnablePauseAndContinue();
});
}
}
}