C# Quartz.NET 配置问题详解

最新项目中的windowService全部换成Quartz.NET和TopShelf,总结了一下配置的过程,写个比较详细的教程

1.下载和安装Quartz.NET和TopShelf

直接在NuGet里面敲Quartz.netTopShelf 安装到自己项目就可以了 ,建议直接用NuGet,毕竟版本和插件管理是比较麻烦的事,Ps:TopShelf是将任何一个函数变成一个window 服务的工具,啥都可以变成服务

安装Quartz.NET

image

安装 TopShelf

image

首先是另一位大神的微博:http://www.cnblogs.com/jys509/p/4628926.html (微博很清新,内容很详细,当初我是看这里装的)

源码下载:Quartz 2.3 示例源码下载 

Quartz.NET 官网地址:http://www.quartz-scheduler.net/ 

Quartz.NET 官方使用教程地址:http://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/using-quartz.html (看翻译好的不如自己边机翻边自己看,也比看翻译好的舒服,别人都嚼过了怎么会香)

Quartz.NET 官网安装教程地址:http://www.quartz-scheduler.net/documentation/quartz-2.x/quick-start.html

 2.配置QuartZ

初始配置

对于QuartZ初始配置的方式有三种:

1.app.config里面直接进行配置(推荐)

先在  <configSections>目录下加配置,如下内容,log4net和entityFramework 是我们项目自己用的,可以无视

1   <configSections>
2     <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net, Version=1.2.13.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a" />
3     <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
4     <section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
5     <sectionGroup name="common">
6       <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging"/>
7     </sectionGroup>
8   </configSections>

然后在<configuration>根目录下加入<quartz>目录就可以了,这种方式比较方便,也统一了config

1   <quartz>
2     <add key="quartz.plugin.xml.fileNames" value="~/quartz_jobs.xml"/>
3     <add key="quartz.plugin.xml.type" value="Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz"/>
4     <add key="quartz.scheduler.instanceName" value=" EDMServiceQuartzTest"/>
5     <add key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz"/>
6     <add key="quartz.threadPool.threadCount" value="10"/>
7     <add key="quartz.threadPool.threadPriority" value="Normal"/>
8   </quartz>

 2.添加quartz.config文件或者在代码中配置文件

quartz.config:文件大概长这样,直接放到根目录就可以了,官网demo里面是没有的,所以不太建议用这种方法

# You can configure your scheduler in either <quartz> configuration section  
# or in quartz properties file  
# Configuration section has precedence  
  
quartz.scheduler.instanceName = ServerScheduler  
  
# 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  

记得要在属性-复制到输出目录,改成始终复制

image

代码中配置文件:这种是最不推荐的了,但是官网里面有demo,Example15,所以就放出来看看,需要动态配置的可以看下,代码如下(Example15)

  1 using System.Collections.Specialized;
  2 using System.Threading;
  3 
  4 using Common.Logging;
  5 
  6 using Quartz.Impl;
  7 using Quartz.Impl.Calendar;
  8 
  9 #region License
 10 /* 
 11  * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved. 
 12  * 
 13  * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
 14  * use this file except in compliance with the License. You may obtain a copy 
 15  * of the License at 
 16  * 
 17  *   http://www.apache.org/licenses/LICENSE-2.0 
 18  *   
 19  * Unless required by applicable law or agreed to in writing, software 
 20  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
 21  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
 22  * License for the specific language governing permissions and limitations 
 23  * under the License.
 24  * 
 25  */
 26 #endregion
 27 
 28 using System.Collections.Specialized;
 29 using System.Threading;
 30 
 31 using Common.Logging;
 32 
 33 using Quartz.Impl;
 34 using Quartz.Impl.Calendar;
 35 
 36 namespace Quartz.Examples.Example15
 37 {
 38     /// <summary>
 39     /// This example will demonstrate how configuration can be
 40     /// done using an XML file.
 41     /// </summary>
 42     /// <author>Marko Lahma (.NET)</author>
 43     public class XmlConfigurationExample : IExample
 44     {
 45         public string Name
 46         {
 47             get { return GetType().Name; }
 48         }
 49 
 50         public void Run()
 51         {
 52             ILog log = LogManager.GetLogger(typeof(XmlConfigurationExample));
 53 
 54             log.Info("------- Initializing ----------------------");
 55 
 56             // First we must get a reference to a scheduler
 57             NameValueCollection properties = new NameValueCollection();
 58             properties["quartz.scheduler.instanceName"] = "XmlConfiguredInstance";
 59             
 60             // set thread pool info
 61             properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";
 62             properties["quartz.threadPool.threadCount"] = "5";
 63             properties["quartz.threadPool.threadPriority"] = "Normal";
 64 
 65             // job initialization plugin handles our xml reading, without it defaults are used
 66             properties["quartz.plugin.xml.type"] = "Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz";
 67             properties["quartz.plugin.xml.fileNames"] = "~/quartz_jobs.xml";
 68 
 69 
 70             ISchedulerFactory sf = new StdSchedulerFactory(properties);
 71             IScheduler sched = sf.GetScheduler();
 72             
 73             // we need to add calendars manually, lets create a silly sample calendar
 74             var dailyCalendar = new DailyCalendar("00:01", "23:59");
 75             dailyCalendar.InvertTimeRange = true;
 76             sched.AddCalendar("cal1", dailyCalendar, false, false);
 77 
 78             log.Info("------- Initialization Complete -----------");
 79 
 80             // all jobs and triggers are now in scheduler
 81 
 82 
 83             // Start up the scheduler (nothing can actually run until the 
 84             // scheduler has been started)
 85             sched.Start();
 86             log.Info("------- Started Scheduler -----------------");
 87 
 88             // wait long enough so that the scheduler as an opportunity to 
 89             // fire the triggers
 90             log.Info("------- Waiting 30 seconds... -------------");
 91 
 92             try
 93             {
 94                 Thread.Sleep(30*1000);
 95             }
 96             catch (ThreadInterruptedException)
 97             {
 98             }
 99 
100             // shut down the scheduler
101             log.Info("------- Shutting Down ---------------------");
102             sched.Shutdown(true);
103             log.Info("------- Shutdown Complete -----------------");
104         }
105     }
106 }
Example15

2.配置Trigger和Job

1.通过quartz_jobs.xml配置(推荐)

刚刚下载好的项目里面是没有这个文件的,可以直接新建一个或者直接把官方Demo里面的文件复制过来,大概长这样

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 
 3 <job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData"
 4         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5                  version="2.0">
 6 
 7   <processing-directives>
 8     <overwrite-existing-data>true</overwrite-existing-data>
 9   </processing-directives>
10 
11   <schedule>
12     
13     <job>
14       <name>jobName1</name>
15       <group>jobGroup1</group>
16       <description>jobDesciption1</description>
17       <job-type>Quartz.Examples.Example15.SimpleJob, Quartz.Examples</job-type>
18       <durable>true</durable>
19       <recover>false</recover>
20       <job-data-map>
21         <entry>
22           <key>key0</key>
23           <value>value0</value>
24         </entry>
25         <entry>
26           <key>key1</key>
27           <value>value1</value>
28         </entry>
29         <entry>
30           <key>key2</key>
31           <value>value2</value>
32         </entry>
33       </job-data-map>
34     </job>
35     
36     <trigger>
37       <simple>
38         <name>simpleName</name>
39         <group>simpleGroup</group>
40         <description>SimpleTriggerDescription</description>
41         <job-name>jobName1</job-name>
42         <job-group>jobGroup1</job-group>
43         <start-time>1982-06-28T18:15:00.0Z</start-time>
44         <end-time>2020-05-04T18:13:51.0Z</end-time>
45         <misfire-instruction>SmartPolicy</misfire-instruction>
46         <repeat-count>100</repeat-count>
47         <repeat-interval>3000</repeat-interval>
48       </simple>
49     </trigger>
50 
51   </schedule>
52   
53 </job-scheduling-data>
quartz_jobs.xml

首先要在1里面添加一个节点 quartz.plugin.xml.fileNames=~/quartz_jobs.xml,然后放入xml就可以了

节点的具体用途可以看看最上面另一个文章的链接<trigger>节点的配置推荐<cron>

要注意的是配置<trigger><job> 的时候和每个节点要按照一定的顺序,

比如<name></name>必须在<job-name></job-name>前面 否则就会出错,具体的看官方demo里面的quartz_jobs.xml,试一试就知道了是否可以添加了(自己项目为啥出不来?笔者也在研究)

2.直接在代码里面配置

官网Demo里面很多都是在代码里面编写的,不太推荐,但是这种初始化的风格的确可以拿来学习一下。拿几个例子看下:

官网的HelloJob(Example1)
 1 #region License
 2 
 3 /* 
 4  * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved. 
 5  * 
 6  * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
 7  * use this file except in compliance with the License. You may obtain a copy 
 8  * of the License at 
 9  * 
10  *   http://www.apache.org/licenses/LICENSE-2.0 
11  *   
12  * Unless required by applicable law or agreed to in writing, software 
13  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
14  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
15  * License for the specific language governing permissions and limitations 
16  * under the License.
17  * 
18  */
19 
20 #endregion
21 
22 using System;
23 using System.Threading;
24 
25 using Common.Logging;
26 #if !NET_20
27 #endif
28 using Quartz.Impl;
29 
30 namespace Quartz.Examples.Example1
31 {
32     /// <summary> 
33     /// This Example will demonstrate how to start and shutdown the Quartz 
34     /// scheduler and how to schedule a job to run in Quartz.
35     /// </summary>
36     /// <author>Bill Kratzer</author>
37     /// <author>Marko Lahma (.NET)</author>
38     public class SimpleExample : IExample
39     {
40         public string Name
41         {
42             get { throw new NotImplementedException(); }
43         }
44 
45         public virtual void Run()
46         {
47             ILog log = LogManager.GetLogger(typeof (SimpleExample));
48 
49             log.Info("------- Initializing ----------------------");
50 
51             // First we must get a reference to a scheduler
52             ISchedulerFactory sf = new StdSchedulerFactory();
53             IScheduler sched = sf.GetScheduler();
54 
55             log.Info("------- Initialization Complete -----------");
56 
57 
58             // computer a time that is on the next round minute
59             DateTimeOffset runTime = DateBuilder.EvenMinuteDate(DateTimeOffset.UtcNow);
60 
61             log.Info("------- Scheduling Job  -------------------");
62 
63             // define the job and tie it to our HelloJob class
64             IJobDetail job = JobBuilder.Create<HelloJob>()
65                 .WithIdentity("job1", "group1")
66                 .Build();
67 
68             // Trigger the job to run on the next round minute
69             ITrigger trigger = TriggerBuilder.Create()
70                 .WithIdentity("trigger1", "group1")
71                 .StartAt(runTime)
72                 .Build();
73 
74             // Tell quartz to schedule the job using our trigger
75             sched.ScheduleJob(job, trigger);
76             log.Info(string.Format("{0} will run at: {1}", job.Key, runTime.ToString("r")));
77 
78             // Start up the scheduler (nothing can actually run until the 
79             // scheduler has been started)
80             sched.Start();
81             log.Info("------- Started Scheduler -----------------");
82 
83             // wait long enough so that the scheduler as an opportunity to 
84             // run the job!
85             log.Info("------- Waiting 65 seconds... -------------");
86 
87             // wait 65 seconds to show jobs
88             Thread.Sleep(TimeSpan.FromSeconds(65));
89 
90             // shut down the scheduler
91             log.Info("------- Shutting Down ---------------------");
92             sched.Shutdown(true);
93             log.Info("------- Shutdown Complete -----------------");
94         }
95     }
96 }
Example1
Example5:一个job怎么关联两个trigger
  1 #region License
  2 
  3 /* 
  4  * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved. 
  5  * 
  6  * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
  7  * use this file except in compliance with the License. You may obtain a copy 
  8  * of the License at 
  9  * 
 10  *   http://www.apache.org/licenses/LICENSE-2.0 
 11  *   
 12  * Unless required by applicable law or agreed to in writing, software 
 13  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
 14  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
 15  * License for the specific language governing permissions and limitations 
 16  * under the License.
 17  * 
 18  */
 19 
 20 #endregion
 21 
 22 using System;
 23 using System.Threading;
 24 
 25 using Common.Logging;
 26 
 27 using Quartz.Impl;
 28 
 29 namespace Quartz.Examples.Example5
 30 {
 31     /// <summary> 
 32     /// Demonstrates the behavior of <see cref="PersistJobDataAfterExecutionAttribute" />, 
 33     /// as well as how misfire instructions affect the firings of triggers of
 34     /// that have <see cref="DisallowConcurrentExecutionAttribute" /> present - 
 35     /// when the jobs take longer to execute that the frequency of the trigger's
 36     /// repetition.
 37     /// </summary>
 38     /// <remarks>
 39     /// <para>
 40     /// While the example is running, you should note that there are two triggers
 41     /// with identical schedules, firing identical jobs. The triggers "want" to fire
 42     /// every 3 seconds, but the jobs take 10 seconds to execute. Therefore, by the
 43     /// time the jobs complete their execution, the triggers have already "misfired"
 44     /// (unless the scheduler's "misfire threshold" has been set to more than 7
 45     /// seconds). You should see that one of the jobs has its misfire instruction
 46     /// set to <see cref="MisfireInstruction.SimpleTrigger.RescheduleNowWithExistingRepeatCount" />,
 47     /// which causes it to fire immediately, when the misfire is detected. The other
 48     /// trigger uses the default "smart policy" misfire instruction, which causes
 49     /// the trigger to advance to its next fire time (skipping those that it has
 50     /// missed) - so that it does not refire immediately, but rather at the next
 51     /// scheduled time.
 52     /// </para>
 53     /// </remarks>
 54     /// <author><a href="mailto:bonhamcm@thirdeyeconsulting.com">Chris Bonham</a></author>
 55     /// <author>Marko Lahma (.NET)</author>
 56     public class MisfireExample : IExample
 57     {
 58         public string Name
 59         {
 60             get { throw new NotImplementedException(); }
 61         }
 62 
 63         public virtual void Run()
 64         {
 65             ILog log = LogManager.GetLogger(typeof (MisfireExample));
 66 
 67             log.Info("------- Initializing -------------------");
 68 
 69             // First we must get a reference to a scheduler
 70             ISchedulerFactory sf = new StdSchedulerFactory();
 71             IScheduler sched = sf.GetScheduler();
 72 
 73             log.Info("------- Initialization Complete -----------");
 74 
 75             log.Info("------- Scheduling Jobs -----------");
 76 
 77             // jobs can be scheduled before start() has been called
 78 
 79             // get a "nice round" time a few seconds in the future...
 80 
 81             DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(null, 15);
 82 
 83             // statefulJob1 will run every three seconds
 84             // (but it will delay for ten seconds)
 85             IJobDetail job = JobBuilder.Create<StatefulDumbJob>()
 86                 .WithIdentity("statefulJob1", "group1")
 87                 .UsingJobData(StatefulDumbJob.ExecutionDelay, 10000L)
 88                 .Build();
 89 
 90             ISimpleTrigger trigger = (ISimpleTrigger) TriggerBuilder.Create()
 91                                                           .WithIdentity("trigger1", "group1")
 92                                                           .StartAt(startTime)
 93                                                           .WithSimpleSchedule(x  => x.WithIntervalInSeconds(3).RepeatForever())
 94                                                           .Build();
 95 
 96             DateTimeOffset ft = sched.ScheduleJob(job, trigger);
 97             log.Info(string.Format("{0} will run at: {1} and repeat: {2} times, every {3} seconds", job.Key, ft.ToString("r"), trigger.RepeatCount, trigger.RepeatInterval.TotalSeconds));
 98 
 99             // statefulJob2 will run every three seconds
100             // (but it will delay for ten seconds - and therefore purposely misfire after a few iterations)
101             job = JobBuilder.Create<StatefulDumbJob>()
102                 .WithIdentity("statefulJob2", "group1")
103                 .UsingJobData(StatefulDumbJob.ExecutionDelay, 10000L)
104                 .Build();
105 
106             trigger = (ISimpleTrigger) TriggerBuilder.Create()
107                                            .WithIdentity("trigger2", "group1")
108                                            .StartAt(startTime)
109                                            .WithSimpleSchedule(x => x
110                                                                  .WithIntervalInSeconds(3)
111                                                                  .RepeatForever()
112                                                                  .WithMisfireHandlingInstructionNowWithExistingCount()) // set misfire instructions
113                                            .Build();
114             ft = sched.ScheduleJob(job, trigger);
115 
116             log.Info(string.Format("{0} will run at: {1} and repeat: {2} times, every {3} seconds", job.Key, ft.ToString("r"), trigger.RepeatCount, trigger.RepeatInterval.TotalSeconds));
117 
118             log.Info("------- Starting Scheduler ----------------");
119 
120             // jobs don't start firing until start() has been called...
121             sched.Start();
122 
123             log.Info("------- Started Scheduler -----------------");
124 
125             try
126             {
127                 // sleep for ten minutes for triggers to file....
128                 Thread.Sleep(TimeSpan.FromMinutes(10));
129             }
130             catch (ThreadInterruptedException)
131             {
132             }
133 
134             log.Info("------- Shutting Down ---------------------");
135 
136             sched.Shutdown(true);
137 
138             log.Info("------- Shutdown Complete -----------------");
139 
140             SchedulerMetaData metaData = sched.GetMetaData();
141             log.Info(string.Format("Executed {0} jobs.", metaData.NumberOfJobsExecuted));
142         }
143     }
144 }
Example15

最后,无论是哪种配置Trigger和Job的方法(xml或者代码)都要记住以下几点:

1.每个Job能对应多个Trigger,但是每个Trigger只能对应一个Job,所以建议把触发时间相同的作业放在一个Job里面也许会比较好,

2.Job配置到多个Trigger时需要配置 <durable>true</durable> 代码里面的是对应的是 .StoreDurably(),否则会报错

三.Job和Trigger入门

过几天会补上

posted @ 2015-08-21 17:21  topucCode  阅读(3087)  评论(0编辑  收藏  举报