Quartz.NET是一个开源的作业调度框架,非常适合在平时的工作中,定时轮询数据库同步,定时邮件通知,定时处理数据等。Quartz.NET允许开发人员根据时间间隔(或天)来调度作业。它实现了作业和触发器的多对多关系,还能把多个作业与不同的触发器关联。整合了 Quartz.NET的应用程序可以重用来自不同事件的作业,还可以为一个事件组合多个作业。
官方学习文档:http://www.quartz-scheduler.net/documentation/index.html
使用实例介绍:https://www.quartz-scheduler.net/documentation/quartz-3.x/quick-start.html
官方使用教程:Quartz.NET - Quartz.NET 3.x 教程
官方教程译文:Quartz.NET 3.x 教程
Quartz.NET的快速入门指南
欢迎来到Quartz.NET的快速入门指南。当您阅读本指南时,您将看到以下详细信息:
- 下载Quartz.NET
- 安装Quartz.NET
- 根据您自己的特殊需要配置Quartz
- 启动示例应用程序
一、下载并安装
您可以下载zip文件,也可以使用NuGet包。NuGet包只包含运行Quartz所需的二进制文件。zip文件附带源代码、示例和Quartz。NET服务器示例应用程序。
1、安装包版本
简约版:下载Quartz.NET,将其解压缩到某个地方,从bin目录获取Quartz.dll和Common.Logging.dll并开始使用它们。
Quartz只依赖于称为Common的第三方库。日志(其中包含日志抽象,允许您使用最适合您的日志提供程序)。你需要在你的应用程序二进制文件旁边有Quartz.dll和Commong.Logging.dll才能成功运行Quartz.NET。所以只需将它们作为引用添加到使用它们的Visual Studio项目中。您可以从path bin\your-target-frame -version\release\Quartz中提取的归档文件中找到这些dll。
2、NuGet包安装
只需启动Visual Studio(使用NuGet安装),并从包管理器扩展名中添加对包Quartz的引用:
- 右键单击项目的引用,并选择Manage NuGet Packages…
- 从左侧选择在线类别
- 在右上角输入Quartz,搜索并回车
- 选择Quartz.NET从搜索结果中点击安装
- 完成了!
或从NuGet命令行:
Install-Package Quartz
如果您想添加JSON序列化,只需添加Quartz.Serialization.Json以同样的方式打包。
3、Configuration 配置
这才是重点!Quartz.NET是一个非常可配置的库。提供Quartz有三种方式(它们并不相互排斥).NET配置信息:
- 通过向调度器工厂提供NameValueCollection参数,以编程方式实现
- 通过标准youapp.exe。配置配置文件使用quartz-element(完整的.net框架)
- quartz.config在你的应用程序的根目录下(适用于.net核心和完整的.net框架)
您可以在Quartz.NET zip文件中找到所有这些备选方案的示例。
基本的Quartz.config是这样的:
quartz.scheduler.instanceName = MyScheduler
quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz
quartz.threadPool.threadCount = 3
记住将Visual Studio的文件属性页上的Copy设置为Output目录,以便始终保持Copy值。否则,如果配置不在构建目录中,将看不到它。
该配置创建的调度器具有以下特点:
- quartz.scheduler.instanceName —— 这个调度程序的名称将是“MyScheduler”。
- quartz.threadPool.threadCount —— 最多可以同时运行3个作业。
- quartz.jobStore.type —— 所有Quartz的数据,例如作业和触发器的详细信息,都保存在内存中(而不是数据库中)。即使您有一个数据库,并且希望与Quartz一起使用它,我建议您在通过使用数据库打开一个全新的维度之前,先让Quartz与RamJobStore一起工作。
实际上你不需要定义这些属性,如果你不想,Quartz.NET具有健全的默认设置
二、举一个小例子
现在您已经下载并安装了Quartz,接下来就可以启动并运行示例应用程序了。下面的代码获得调度程序的一个实例,启动它,然后关闭它:
Program.cs
using System;
using System.Threading.Tasks;
using Quartz;
using Quartz.Impl;
namespace QuartzSampleApp
{
public class Program
{
private static void Main(string[] args)
{
// 触发器异步计算
RunProgram().GetAwaiter().GetResult();
}
private static async Task RunProgram()
{
try
{
// 从工厂获取调度程序实例
NameValueCollection props = new NameValueCollection
{
{ "quartz.serializer.type", "binary" }
};
StdSchedulerFactory factory = new StdSchedulerFactory(props);
IScheduler scheduler = await factory.GetScheduler();
// 然后开始
await scheduler.Start();
// 线程休眠60秒,是为了更好的观察
await Task.Delay(TimeSpan.FromSeconds(60));
// 最后关闭调度程序
await scheduler.Shutdown();
}
catch (SchedulerException se)
{
await Console.Error.WriteLineAsync(se.ToString());
}
}
}
}
从Quartz 3.0开始,当scheduler. shutdown()之后没有代码可执行时,应用程序将终止,因为不会有任何活动线程。如果您希望调度程序在任务完成后也能继续运行,则应手动阻止退出应用程序。延迟和关机已经处理。
现在运行程序不会显示任何内容。当10秒过去了,程序将会终止。让我们向控制台添加一些日志记录。
添加日志记录
LibLog可以配置为使用不同的日志框架;即Log4Net、NLog和Serilog。
当LibLog没有检测到任何其他日志框架时,它将保持静默。如果您还没有准备好日志框架,我们可以配置一个自定义日志记录器提供程序,它只记录到控制台并显示输出。
将下列代码添加到 Program.cs
LogProvider.SetCurrentLogProvider(new ConsoleLogProvider());
private class ConsoleLogProvider : ILogProvider
{
public Logger GetLogger(string name)
{
return (level, func, exception, parameters) =>
{
if (level >= LogLevel.Info && func != null)
{
Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters);
}
return true;
};
}
public IDisposable OpenNestedContext(string message)
{
throw new NotImplementedException();
}
public IDisposable OpenMappedContext(string key, string value)
{
throw new NotImplementedException();
}
}
给程序添加调度任务
现在,我们应该得到更多的信息,当我们开始应用程序。
[12.51.10] [Info] Quartz.NET properties loaded from configuration file 'C:\QuartzSampleApp\quartz.config'
[12.51.10] [Info] Initialized Scheduler Signaller of type: Quartz.Core.SchedulerSignalerImpl
[12.51.10] [Info] Quartz Scheduler v.0.0.0.0 created.
[12.51.10] [Info] RAMJobStore initialized.
[12.51.10] [Info] Scheduler meta-data: Quartz Scheduler (v0.0.0.0) 'MyScheduler' with instanceId 'NON_CLUSTERED'
Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally.
NOT STARTED.
Currently in standby mode.
Number of jobs executed: 0
Using thread pool 'Quartz.Simpl.DefaultThreadPool' - with 3 threads.
Using job-store 'Quartz.Simpl.RAMJobStore' - which does not support persistence. and is not clustered.
[12.51.10] [Info] Quartz scheduler 'MyScheduler' initialized
[12.51.10] [Info] Quartz scheduler version: 0.0.0.0
[12.51.10] [Info] Scheduler MyScheduler_$_NON_CLUSTERED started.
我们需要一个简单的测试作业来测试功能,让我们创建输出问候到控制台的HelloJob。
public class HelloJob : IJob
{
public async Task Execute(IJobExecutionContext context)
{
await Console.Out.WriteLineAsync("来自HelloJob的问候!");
}
}
您需要在Start()方法之后、在Task.Delay之前编写代码。
// 定义作业并将其绑定到HelloJob类
IJobDetail job = JobBuilder.Create<HelloJob>()
.WithIdentity("job1", "group1")
.Build();
// 触发作业现在运行,然后每10秒重复一次
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(10)
.RepeatForever())
.Build();
// 告诉quartz使用我们的触发器来安排工作
await scheduler.ScheduleJob(job, trigger);
完整的控制台应用程序现在看起来是这样的:
using System;
using System.Threading.Tasks;
using Quartz;
using Quartz.Impl;
using Quartz.Logging;
namespace QuartzSampleApp
{
public class Program
{
private static void Main(string[] args)
{
LogProvider.SetCurrentLogProvider(new ConsoleLogProvider());
RunProgramRunExample().GetAwaiter().GetResult();
Console.WriteLine("按任意键关闭应用程序");
Console.ReadKey();
}
private static async Task RunProgramRunExample()
{
try
{
// 从工厂获取调度程序实例
NameValueCollection props = new NameValueCollection
{
{ "quartz.serializer.type", "binary" }
};
StdSchedulerFactory factory = new StdSchedulerFactory(props);
IScheduler scheduler = await factory.GetScheduler();
// 然后开始
await scheduler.Start();
// 定义作业并将其绑定到HelloJob类
IJobDetail job = JobBuilder.Create<HelloJob>()
.WithIdentity("job1", "group1")
.Build();
// 触发作业现在运行,然后每10秒重复一次
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(10)
.RepeatForever())
.Build();
// 告诉quartz使用我们的触发器来安排工作
await scheduler.ScheduleJob(job, trigger);
// 线程休眠60秒,是为了更好的观察
await Task.Delay(TimeSpan.FromSeconds(60));
// 最后关闭调度程序
await scheduler.Shutdown();
}
catch (SchedulerException se)
{
Console.WriteLine(se);
}
}
// 简单的日志提供程序来获取控制台的内容
private class ConsoleLogProvider : ILogProvider
{
public Logger GetLogger(string name)
{
return (level, func, exception, parameters) =>
{
if (level >= LogLevel.Info && func != null)
{
Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters);
}
return true;
};
}
public IDisposable OpenNestedContext(string message)
{
throw new NotImplementedException();
}
public IDisposable OpenMappedContext(string key, string value)
{
throw new NotImplementedException();
}
}
}
public class HelloJob : IJob
{
public async Task Execute(IJobExecutionContext context)
{
await Console.Out.WriteLineAsync("来自 HelloJob 的问候!");
}
}
}
现在去探索一下Quartz.NET吧!您可以继续阅读教程。