Quartz.Net AnnualCalendar And PlugInConfigure

正如標題所示,文章主要是圍繞Quartz.Net做業調度框架話題展開的,內容出自博主學習官方Examples的學習心得與體會,文中不免會有錯誤之處,還請指出得以指教。web

一: Calendarapp

前面演示過根據秒-分-時 日-月-星期等觸發時機來定義一個輪詢的做業調度,在實際生活中,除此以外還有根據日從來調度做業,根據日曆定義觸發輪詢週期也是比較經常使用常見的功能。
框架

在Quartz.Net中日曆是由AnnualCalendar類定義的,實例化一個AnnualCalendar對象,往這個對象添加自定義的日期構成自定義的一個日曆觸發時機集合。tcp

舉個例子:ide

 

           //日曆對象
            AnnualCalendar holidays = new AnnualCalendar();

            // 元旦
            DateTime NewYearDay = new DateTime(DateTime.UtcNow.Year, 1, 1);
            holidays.SetDayExcluded(NewYearDay , true);

            // 國慶節
            DateTime NationalDay= new DateTime(DateTime.UtcNow.Year, 10, 1);
            holidays.SetDayExcluded(NationalDay, true);

            // 光棍節
            DateTime SinglesDay= new DateTime(DateTime.UtcNow.Year, 11, 11);
            holidays.SetDayExcluded(SinglesDay, true);

 

有了日曆對象以後,須要將日曆對象附加到調度實例上,而且在觸發器中使用ModifiedByCalendar("日曆對象")來指定按照日曆對象進行調度。學習

下面貼出根據日曆對象指定的日期進行做業調度的代碼(僅供參考):ui

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Quartz.Impl.Calendar;
using Quartz.Impl;
using Common.Logging;

namespace Quartz.Examples
{
    /// <summary> 
    /// This example will demonstrate how calendars can be used 
    /// to exclude periods of time when scheduling should not
    /// take place.
    /// 一個根據日曆(節假日)來設定調度做業的演示
    /// </summary>
    /// <author>Marko Lahma (.NET)</author>
    public class CalendarExample : IExample
    {
        public string Name
        {
            get { return GetType().Name; }
        }

        public virtual void Run()
        {
            ILog log = LogManager.GetLogger(typeof(CalendarExample));

            log.Info("------- Initializing ----------------------");

            // First we must get a reference to a scheduler
            ISchedulerFactory sf = new StdSchedulerFactory();
            IScheduler sched = sf.GetScheduler();

            log.Info("------- Initialization Complete -----------");

            log.Info("------- Scheduling Jobs -------------------");

            // Add the holiday calendar to the schedule   //就是自定義節假日   好比咱們能夠事先根據日曆設定7月4號,10月31號,12月25號做爲調度時機
            AnnualCalendar holidays = new AnnualCalendar();

            // fourth of July (July 4)
            DateTime fourthOfJuly = new DateTime(DateTime.UtcNow.Year, 7, 4);
            holidays.SetDayExcluded(fourthOfJuly, true);

            // halloween (Oct 31)
            DateTime halloween = new DateTime(DateTime.UtcNow.Year, 10, 31);//10月31號
            holidays.SetDayExcluded(halloween, true);

            // christmas (Dec 25)
            DateTime christmas = new DateTime(DateTime.UtcNow.Year, 12, 25);
            holidays.SetDayExcluded(christmas, true);

            // tell the schedule about our holiday calendar
            sched.AddCalendar("holidays", holidays, false, false);

           
            //設定開啓調度日曆的時間
            DateTimeOffset runDate = DateBuilder.DateOf(10, 0, 0, 31, 10);//10.31早上10點開啓調度做業

            IJobDetail job = JobBuilder.Create<SimpleJob>()
                .WithIdentity("job1", "group1")
                .Build();

            ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create()
                                                          .WithIdentity("trigger1", "group1")
                                                          .StartAt(runDate)
                                                          .WithSimpleSchedule(x => x.WithIntervalInHours(1).RepeatForever())
                                                          .ModifiedByCalendar("holidays")
                                                          .Build();

            // schedule the job and print the first run date
            DateTimeOffset firstRunTime = sched.ScheduleJob(job, trigger);

            
            log.Info(string.Format("{0} will run at: {1} and repeat: {2} times, every {3} seconds", job.Key, firstRunTime.ToString("r"), trigger.RepeatCount, trigger.RepeatInterval.TotalSeconds));

            log.Info("------- Starting Scheduler ----------------");
            sched.Start();
            log.Info("------- Waiting 30 seconds... --------------");
            try
            {
                // wait 30 seconds to show jobs
                Thread.Sleep(30 * 1000);
                // executing...
            }
            catch (ThreadInterruptedException)
            {
            }

            // shut down the scheduler
            log.Info("------- Shutting Down ---------------------");
            sched.Shutdown(true);
            log.Info("------- Shutdown Complete -----------------");

            SchedulerMetaData metaData = sched.GetMetaData();
            log.Info(string.Format("Executed {0} jobs.", metaData.NumberOfJobsExecuted));
        }
    }
}
AnnualCalendar

二:監聽對象this

在Quartz.Net框架中提供了一個監聽器IJobListener接口,實現該接口實例化一個子類,這個子類能夠監聽一個做業id來觸發自己的void JobWasExecuted(IJobExecutionContext inContext, JobExecutionException inException)方法:這個方法裏面帶了IJobExecutionContext inContext參數,inContext.Scheduler其實就是程序的調度實例,咱們知道經過調度實例能夠添加做業以及觸發器(定製一個輪詢的調度任務)而且Start()開啓執行任務。spa

這樣看來,經過實現IJobListener接口獲得監聽器類中的JobWasExecuted()方法裏能夠再次定義輪詢調度做業。.net

好比當須要知足如下需求時可使用監聽器來實現:

=>在A任務順利開啓執行後,輪詢調度B任務。(此時B任務就定義在監聽器類裏面)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Quartz.Impl.Matchers;
using Quartz.Impl;
using Common.Logging;

namespace Quartz.Examples
{
    
    public class ListenerExample : IExample
    {
        public string Name
        {
            get { return GetType().Name; }
        }

        public virtual void Run()
        {
            ILog log = LogManager.GetLogger(typeof(ListenerExample));

            log.Info("------- Initializing ----------------------");

            // First we must get a reference to a scheduler
            ISchedulerFactory sf = new StdSchedulerFactory();
            IScheduler sched = sf.GetScheduler();

            log.Info("------- Initialization Complete -----------");

            log.Info("------- Scheduling Jobs -------------------");

            // schedule a job to run immediately
            IJobDetail job = JobBuilder.Create<SimpleJob1>()
                .WithIdentity("job1")
                .Build();

            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity("trigger1")
                .StartNow()
                .Build();
            //IJobListener監聽器接口,實現該接口獲得自定義的Job1Listener類,在該類中實現JobWasExecuted()方法,在方法中能夠添加做業觸發器

            //監聽類的意義更在於在一個做業成功運行以後,觸發綁定的另一些操做,這些操做在監聽類中定義並調度。
            // Set up the listener
            //設定監聽程序,實例話Job1Listener()監聽類
            IJobListener listener = new Job1Listener();
            IMatcher<JobKey> matcher = KeyMatcher<JobKey>.KeyEquals(job.Key);
            sched.ListenerManager.AddJobListener(listener, matcher);//根據做業key爲響應做業添加監聽

         
            sched.ScheduleJob(job, trigger);
            log.Info("------- Starting Scheduler ----------------");
            sched.Start();
            log.Info("------- Waiting 30 seconds... --------------");
            try
            {
                // wait 30 seconds to show jobs
                Thread.Sleep(TimeSpan.FromSeconds(30));
                // executing...
            }
            catch (ThreadInterruptedException)
            {
            }


            // shut down the scheduler
            log.Info("------- Shutting Down ---------------------");
            sched.Shutdown(true);
            log.Info("------- Shutdown Complete -----------------");

            SchedulerMetaData metaData = sched.GetMetaData();
            log.Info(string.Format("Executed {0} jobs.", metaData.NumberOfJobsExecuted));
        }
    }
}
ListenerExample
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.Logging;

namespace Quartz.Examples
{
    ///監聽程序能夠附加到做業中,附加了監聽器的做業在進行調度的時候,準備執行,否決,執行完畢三個狀態
    ///而且在監聽程序能夠實例化IJobDetail類建立新做業
    public class Job1Listener : IJobListener
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(Job1Listener));

        public virtual string Name
        {
            get { return "job1_to_job2"; }
        }

        public virtual void JobToBeExecuted(IJobExecutionContext inContext)
        {
            log.Info("Job1Listener says: Job Is about to be 執行.");//執行
        }

        public virtual void JobExecutionVetoed(IJobExecutionContext inContext)
        {
            log.Info("Job1Listener says: Job Execution was 否決.");//否決
        }

        public virtual void JobWasExecuted(IJobExecutionContext inContext, JobExecutionException inException)
        {
            log.Info("Job1Listener says: Job was 執行 完畢.");

            // Simple job #2
            //監聽程序調度做業
            IJobDetail job2 = JobBuilder.Create<SimpleJob2>()
                .WithIdentity("job2")
                .Build();

            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity("job2Trigger")
                .StartNow()
                .Build();

            try
            {
                // schedule the job to run!
                inContext.Scheduler.ScheduleJob(job2, trigger);
            }
            catch (SchedulerException e)
            {
                log.Warn("Unable to schedule job2!");
                Console.Error.WriteLine(e.StackTrace);
            }
        }
    }
}
View Code

三:插件配置

官方給出的名字叫作插件,其實我認爲,這只是一種關於如何調度做業的配置。

有三種配置方式:

1.經過代碼實例化NameValueCollection對象,往NameValueCollection對象以鍵值對形式賦值,而後在調度工廠對象中傳入該NameValueCollection對象獲得調度實例。

            var properties = new NameValueCollection();
            properties["quartz.plugin.triggHistory.type"] = "Quartz.Plugin.History.LoggingJobHistoryPlugin";

            properties["quartz.plugin.jobInitializer.type"] = "Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin";//插件
            properties["quartz.plugin.jobInitializer.fileNames"] = "quartz_jobs.xml";//讀取這個配置文件
            properties["quartz.plugin.jobInitializer.failOnFileNotFound"] = "true";
            properties["quartz.plugin.jobInitializer.scanInterval"] = "120";//120秒一次

            // First we must get a reference to a scheduler
            ISchedulerFactory sf = new StdSchedulerFactory(properties);
            IScheduler sched = sf.GetScheduler();
sched.Start();

經過這樣方式無須再使用代碼定義做業對象IJobDetail以及觸發器ITrigger等,而是經過properties["quartz.plugin.jobInitializer.fileNames"]指定的xml文件來設置:

<?xml version="1.0" encoding="UTF-8"?>

<job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 version="2.0">

  <processing-directives>
    <overwrite-existing-data>true</overwrite-existing-data>
  </processing-directives>

  <schedule>
    
    <job>
      <name>jobName1</name>
      <group>jobGroup1</group>
      <description>jobDesciption1</description>
      <job-type>Quartz.Examples.SimpleJob3, Quartz.Examples</job-type>
      <durable>true</durable>
      <recover>false</recover>
      <job-data-map>
        <entry>
          <key>key0</key>
          <value>value0</value>
        </entry>
        <entry>
          <key>key1</key>
          <value>value1</value>
        </entry>
        <entry>
          <key>key2</key>
          <value>value2</value>
        </entry>
      </job-data-map>
    </job>
    
    <trigger>
      <simple>
        <name>simpleName</name>
        <group>simpleGroup</group>
        <description>SimpleTriggerDescription</description>
        <job-name>jobName1</job-name>
        <job-group>jobGroup1</job-group>
        <start-time>1982-06-28T18:15:00.0Z</start-time>
        <end-time>2020-05-04T18:13:51.0Z</end-time>
        <misfire-instruction>SmartPolicy</misfire-instruction>
        <repeat-count>100</repeat-count>
        <repeat-interval>3000</repeat-interval>
      </simple>
    </trigger>

  </schedule>
  
</job-scheduling-data>
quartz_jobs.xml

 

注意點:

 1.1 quartz_jobs.xml必須設置爲始終複製=>右鍵屬性,複製到輸出目錄選項選擇始終複製

 1.2 要將NameValueCollection對象傳入StdSchedulerFactory工廠中以獲得調試實例對象

       ISchedulerFactory sf = new StdSchedulerFactory(properties);

 

2.經過app.config或者web.config配置文件

經過這種方式定義調度做業的信息將會放置在app.config或web.config配置文件中,在代碼中只須要獲得一個無參的StdSchedulerFactory()實例對象,開啓調度便可:

 

            ISchedulerFactory sf = new StdSchedulerFactory();
            IScheduler sched = sf.GetScheduler();

            // start the schedule 
            sched.Start();

 

app.config配置文件內容:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />
            <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
        <sectionGroup name="common">
            <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
        </sectionGroup>
    </configSections>

    <common>
        <logging>
            <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4net1213">
                <arg key="configType" value="INLINE" />
            </factoryAdapter>
        </logging>
    </common>

    <log4net>
        <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%d [%t] %-5p %l - %m%n" />
            </layout>
        </appender>
        <appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%d [%t] %-5p %l - %m%n" />
            </layout>
        </appender>
        <root>
            <level value="INFO" />
            <appender-ref ref="ConsoleAppender" />
      <!-- uncomment to enable event log appending -->
            <!-- <appender-ref ref="EventLogAppender" /> -->
        </root>
    </log4net>

  <!-- 
    We use quartz.config for this server, you can always use configuration section if you want to.
    Configuration section has precedence here.  
  -->
   
  <quartz>
    <add key="quartz.plugin.triggHistory.type" value="Quartz.Plugin.History.LoggingJobHistoryPlugin"/>
    <add key="quartz.plugin.jobInitializer.type" value="Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin"/>
    <add key="quartz.plugin.jobInitializer.fileNames" value="quartz_jobs.xml"/>
    <add key="quartz.plugin.jobInitializer.failOnFileNotFound" value="true"/>
    <add key="quartz.plugin.jobInitializer.scanInterval" value="120"/>
  </quartz>
   
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Common.Logging" publicKeyToken="af08829b84f0328e" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-1.2.13.0" newVersion="1.2.13.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>
App.config

在app.config中會指定調度任務信息的一個路徑,好比quartz_jobs.xml文件,經過讀取這個xml文件來獲取調度任務。

 2.1 quartz_jobs.xml必須設置爲始終複製=>右鍵屬性,複製到輸出目錄選項選擇始終複製

 

 

3.經過quartz.config配置文件

 

# 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

#--------------------------------*************plugin配置------------------------------------
# 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
quartz.config

 

在代碼中只須要獲得一個無參的StdSchedulerFactory()實例對象,開啓調度便可:

 

 

            ISchedulerFactory sf = new StdSchedulerFactory();
            IScheduler sched = sf.GetScheduler();

            // start the schedule 
            sched.Start();

 

 

 

 3.1 quartz_jobs.xml必須設置爲始終複製=>右鍵屬性,複製到輸出目錄選項選擇始終複製

 3.2 quartz.config必須設置爲始終複製=>右鍵屬性,複製到輸出目錄選項選擇始終複製

相關文章
相關標籤/搜索