Quartz.NET 的应用
🏷️ Quartz
在 Quartz.NET 中学习了该框架的用法。
现需要基于该框架升级原本使用 Windows Service 实现的定时任务功能。
原功能使用自定义的系统任务表来保存定时任务的设置,而 Quartz.NET 则使用了一套自己的表,而且没有提供设置的 UI。
为了尽量减少修改量,所以实现的思想是尽量保留原本的任务增删改查功能。
而且经过调查发现,只需在原本处理的后面增加一个更新 Quart.NET 任务的代码就可以了。
下面是示例代码:
设置工程 QuartzSettingApplication
在该工程中创建 Schedule 但是不启动,将定义好的 Job 增加到 Schedule 中之后就关闭掉该实例。这样修改的设置就可以自动更新到对应的数据库了(这里使用的是 SqlServer)。
实际项目中只需要在原有的任务设置处理后面增加类似如下 Quartz 的设置处理就可以了。csharpusing Quartz; using Quartz.Impl; using Quartz.Logging; using QuartzJobs; using System; using System.Collections.Specialized; using System.Threading.Tasks; namespace QuartzSettingApplication { class Program { static void Main(string[] args) { LogProvider.SetCurrentLogProvider(new ConsoleLogProvider()); // trigger async evaluation RunProgram().GetAwaiter().GetResult(); Console.WriteLine("Press any key to close the application"); Console.ReadKey(); } private static async Task RunProgram() { // Grab the Scheduler instance from the Factory NameValueCollection props = new NameValueCollection { { "quartz.serializer.type", "binary" }, { "quartz.scheduler.instanceName", "MyScheduler" }, { "quartz.jobStore.type", "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz" }, { "quartz.jobStore.driverDelegateType", "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz" }, { "quartz.jobStore.tablePrefix", "QRTZ_" }, { "quartz.jobStore.dataSource", "myDS" }, { "quartz.dataSource.myDS.connectionString", "Data Source=EDG2GYKVF8G5P6Z;Initial Catalog=Quartz;User ID=sa;Password=password;" }, { "quartz.dataSource.myDS.provider", "SqlServer" }, { "quartz.threadPool.threadCount", "3" }, { "quartz.scheduler.instanceId", "AUTO" }, { "quartz.jobStore.clustered", "true" }, }; StdSchedulerFactory factory = new StdSchedulerFactory(props); IScheduler scheduler = await factory.GetScheduler(); // 删除 Jobs for (int i = 0; i <= 2; i++) { if (scheduler.CheckExists(new JobKey($"job{ i + 1}", "group1")).GetAwaiter().GetResult()) { await scheduler.DeleteJob(new JobKey($"job{ i + 1}", "group1")); } } await Task.Delay(TimeSpan.FromSeconds(10)); // 重新添加 Jobs for (int i = 0; i <= 2; i++) { if (!scheduler.CheckExists(new JobKey($"job{ i + 1}", "group1")).GetAwaiter().GetResult()) { // define the job and tie it to our HelloJob class IJobDetail job = JobBuilder.Create<HelloJob>() .WithIdentity($"job{ i + 1}", "group1") .UsingJobData("count", 2) .Build(); // Trigger the job to run now, and then repeat every 10 seconds ITrigger trigger = TriggerBuilder.Create() .WithIdentity($"trigger{ i + 1}", "group1") .StartNow() .WithSimpleSchedule(x => x .WithIntervalInSeconds(10) //.WithRepeatCount(0) .RepeatForever() ) .Build(); // Tell quartz to schedule the job using our trigger await scheduler.ScheduleJob(job, trigger); } } await Task.Delay(TimeSpan.FromSeconds(10)); await scheduler.Shutdown(); } } }
执行 JOB 的工程 QuartzService
这个是执行 Job 的工程,启动后永不关闭。这个工程可以开启多个实例。
需要注意的是,这里启用了集群功能,需要保证开启的实例(包括上面设置 Job 时启动的实例)的设置是一样(除了 quartz.threadPool.threadCount),而且服务器系统时间不能有超过 1 秒的误差。csharpusing Quartz; using Quartz.Impl; using Quartz.Logging; using QuartzJobs; using System; using System.Collections.Specialized; using System.Threading; using System.Threading.Tasks; namespace QuartzService { class Program { static void Main(string[] args) { LogProvider.SetCurrentLogProvider(new ConsoleLogProvider()); // trigger async evaluation RunProgram().GetAwaiter().GetResult(); } private static async Task RunProgram() { try { // Grab the Scheduler instance from the Factory NameValueCollection props = new NameValueCollection { { "quartz.serializer.type", "binary" }, { "quartz.scheduler.instanceName", "MyScheduler" }, { "quartz.jobStore.type", "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz" }, { "quartz.jobStore.driverDelegateType", "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz" }, { "quartz.jobStore.tablePrefix", "QRTZ_" }, { "quartz.jobStore.dataSource", "myDS" }, { "quartz.dataSource.myDS.connectionString", "Data Source=EDG2GYKVF8G5P6Z;Initial Catalog=Quartz;User ID=sa;Password=password;" }, { "quartz.dataSource.myDS.provider", "SqlServer" }, { "quartz.threadPool.threadCount", "3" }, { "quartz.scheduler.instanceId", "AUTO" }, { "quartz.jobStore.clustered", "true" }, }; StdSchedulerFactory factory = new StdSchedulerFactory(props); //StdSchedulerFactory factory = new StdSchedulerFactory(); IScheduler scheduler = await factory.GetScheduler(); // and start it off await scheduler.Start(); await Task.Delay(Timeout.Infinite); // and last shut down the scheduler when you are ready to close your program await scheduler.Shutdown(); } catch (SchedulerException se) { await Console.Error.WriteLineAsync(se.ToString()); } } } }