安装 Quartz 程序包
使用 nuget 命令行安装 Quartz:
Install-Package Quartz
如果使用 JSON 序列化,使用 nuget 安装 Quartz.Serialization.Json。
配置 Quartz
可通过三种方式配置Quartz
- 编程式配置,用 NameValueCollection 为 SchedulerFactory 提供参数
- 通过 app.config 文件,这种方式仅适用于 full .net framework
- 通过 quartz.config,此文件需放在应用程序的根目录,这种方式适用于 full .net framework 和 .net core
程序骨架
以下代码创建 Scheduler 实例,启动它,最后关闭。
using System; using System.Collections.Specialized; 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 { // 从工厂获取 Scheduler 实例 NameValueCollection props = new NameValueCollection { { "quartz.serializer.type", "binary" } }; StdSchedulerFactory factory = new StdSchedulerFactory(props); IScheduler scheduler = await factory.GetScheduler(); // 启动 Scheduler 实例 await scheduler.Start(); // 停60秒看效果 await Task.Delay(TimeSpan.FromSeconds(60)); // 关闭程序前关闭 scheduler await scheduler.Shutdown(); } catch (SchedulerException se) { await Console.Error.WriteLineAsync(se.ToString()); } } } }
通过 StdSchedulerFactory.GetDefaultScheduler() 方法获取到 scheduler 实例后,直到调用 scheduler.Shutdown() 前,应用程序不会退出。因为存在后台线程。
添加日志
Quartz.net 使用 LibLog,可适配 Log4Net,NLog 和Serilog等日志框架。没有检测到这些日志框架时,LibLog不输出内容。下面的自定义 LoggerProvider 在没有使用日志框架的情况下向控制台输出消息:
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(); } }
使用自定义LogProvider:
private static void Main(string[] args) { LogProvider.SetCurrentLogProvider(new ConsoleLogProvider()); // 异步执行 RunProgram().GetAwaiter().GetResult(); }
添加作业
使用 IJob 接口自定义作业
public class HelloJob : IJob { public async Task Execute(IJobExecutionContext context) { await Console.Out.WriteLineAsync("Greetings from HelloJob!"); } }
使用作业,在调用 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);
完整代码
using System; using System.Collections.Specialized; 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()); // 异步执行 RunProgram().GetAwaiter().GetResult(); } private static async Task RunProgram() { try { // 从工厂获取 Scheduler 实例 NameValueCollection props = new NameValueCollection { { "quartz.serializer.type", "binary" } }; StdSchedulerFactory factory = new StdSchedulerFactory(props); IScheduler scheduler = await factory.GetScheduler(); // 启动 Scheduler 实例 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)); // 关闭程序前关闭 scheduler await scheduler.Shutdown(); } catch (SchedulerException se) { await Console.Error.WriteLineAsync(se.ToString()); } } 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("Greetings from HelloJob!"); } } }
程序输出
程序启动后,输出以下内容:
[16:31:41] [Info] Using object serializer: Quartz.Simpl.BinaryObjectSerializer, Quartz [16:31:41] [Info] Initialized Scheduler Signaller of type: Quartz.Core.Scheduler SignalerImpl [16:31:41] [Info] Quartz Scheduler v.3.0.2.0 created. [16:31:41] [Info] RAMJobStore initialized. [16:31:41] [Info] Scheduler meta-data: Quartz Scheduler (v3.0.2.0) ‘QuartzScheduler‘ 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 10 threads. Using job-store ‘Quartz.Simpl.RAMJobStore‘ - which does not support persistence. and is not clustered. [16:31:41] [Info] Quartz scheduler ‘QuartzScheduler‘ initialized [16:31:41] [Info] Quartz scheduler version: 3.0.2.0 [16:31:41] [Info] Scheduler QuartzScheduler_$_NON_CLUSTERED started. Greetings from HelloJob! Greetings from HelloJob! Greetings from HelloJob! Greetings from HelloJob! Greetings from HelloJob! Greetings from HelloJob! Greetings from HelloJob! [16:32:41] [Info] Scheduler QuartzScheduler_$_NON_CLUSTERED shutting down. [16:32:41] [Info] Scheduler QuartzScheduler_$_NON_CLUSTERED paused. [16:32:41] [Info] Scheduler QuartzScheduler_$_NON_CLUSTERED Shutdown complete. 请按任意键继续. . .