最新項目中的windowService所有換成Quartz.NET和TopShelf,總結了一下配置的過程,寫個比較詳細的教程html
直接在NuGet裏面敲Quartz.net和TopShelf 安裝到本身項目就能夠了 ,建議直接用NuGet,畢竟版本和插件管理是比較麻煩的事,Ps:TopShelf是將任何一個函數變成一個window 服務的工具,啥均可以變成服務express
安裝Quartz.NETapache
安裝 TopShelfapp
首先是另外一位大神的微博:http://www.cnblogs.com/jys509/p/4628926.html (微博很清新,內容很詳細,當初我是看這裏裝的)less
源碼下載:Quartz 2.3 示例源碼下載 tcp
Quartz.NET 官網地址:http://www.quartz-scheduler.net/ ide
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工具
對於QuartZ初始配置的方式有三種:學習
先在 <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>
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
記得要在屬性-複製到輸出目錄,改爲始終複製
代碼中配置文件:這種是最不推薦的了,可是官網裏面有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 }
剛剛下載好的項目裏面是沒有這個文件的,能夠直接新建一個或者直接把官方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>
首先要在1裏面添加一個節點 quartz.plugin.xml.fileNames=~/quartz_jobs.xml,而後放入xml就能夠了
節點的具體用途能夠看看最上面另外一個文章的連接,<trigger>節點的配置推薦<cron>
要注意的是配置<trigger><job> 的時候和每一個節點要按照必定的順序,
好比<name></name>必須在<job-name></job-name>前面 不然就會出錯,具體的看官方demo裏面的quartz_jobs.xml,試一試就知道了是否能夠添加了(本身項目爲啥出不來?筆者也在研究)
官網Demo裏面不少都是在代碼裏面編寫的,不太推薦,可是這種初始化的風格的確能夠拿來學習一下。拿幾個例子看下:
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 }
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 }
1.每一個Job能對應多個Trigger,可是每一個Trigger只能對應一個Job,因此建議把觸發時間相同的做業放在一個Job裏面也許會比較好,
2.Job配置到多個Trigger時須要配置 <durable>true</durable> 代碼裏面的是對應的是 .StoreDurably(),不然會報錯
過幾天會補上