About Quartz.Net Build the environment and some example

正如标题所示,文章主要是围绕Quartz.Net做业调度框架话题展开的,内容出自博主学习官方Examples的学习心得与体会,文中不免会有错误之处,还请指出得以指教。框架

在进入Quartz.Net以前,先来看一下Quartz.Net框架运行环境要准备的一些东西.ide

首先须要准备如下程序集:函数

1.Common.Logging学习

2.Common.Logging.Coreui

3.Common.Logging.Log4Net1213spa

4.log4net.net

5.Topshelfcode

6.Quartzorm

须要稍微注意一下彼此版本号要对应,博主的运行环境中依次版本号为(仅供参考):Common.Logging 3.0.0.0 Common.Logging.Core 3.0.0.0,Common.Logging.Log4Net1213 3.0.0.0 ,log4net 1.2.13.0 ,Quartz 2.3.2.0 ,Topshelf 3.1.135.0对象

ps:博主这里新建的控制台程序Quartz.Examples,程序集版本.net framework 4.0

一:接下来进入主题,首先先来看一段代码:

TIP:在接下来的所有例子中main函数都是使用如下代码,因此在贴出代码的时候将再也不重复贴出main函数相关代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Quartz.Util;
using System.Reflection;

namespace Quartz.Examples
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                //反射获得当前运行程序集
                Assembly asm = Assembly.GetExecutingAssembly();
                //获取全部类
                Type[] types = asm.GetTypes();

                IDictionary<int, Type> typeMap = new Dictionary<int, Type>();
                int counter = 1;

                Console.WriteLine("Select example to run: ");
                List<Type> typeList = new List<Type>();
                //循环遍历当前运行程序集的全部类
                foreach (Type t in types)
                {
                    //将实现了IExample接口的类加入到typeList集合中
                    if (new List<Type>(t.GetInterfaces()).Contains(typeof(IExample)))
                    {
                        typeList.Add(t);
                    }
                }

                typeList.Sort(new TypeNameComparer());

                //循环将序号 类名  加入到typeMap字典中
                foreach (Type t in typeList)
                {
                    string counterString = string.Format("[{0}]", counter).PadRight(4);
                    Console.WriteLine("{0} {1} {2}", counterString, t.Namespace.Substring(t.Namespace.LastIndexOf(".") + 1), t.Name);
                    typeMap.Add(counter++, t);
                }

                Console.WriteLine();
                Console.Write("> ");
                //选择要运行的类的序号
                int num = Convert.ToInt32(Console.ReadLine());
                //获取该类的Type
                Type eType = typeMap[num];
                //获得该类的实例
                IExample example = ObjectUtils.InstantiateType<IExample>(eType);
                //运行Run()
                example.Run();
                Console.WriteLine("Example run successfully.");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error running example: " + ex.Message);
                Console.WriteLine(ex.ToString());

            }
            Console.Read();
        }
        /// <summary>
        /// 用于排序的比较器
        /// </summary>
        public class TypeNameComparer : IComparer<Type>
        {
            public int Compare(Type t1, Type t2)
            {
                if (t1.Namespace.Length > t2.Namespace.Length)
                {
                    return 1;
                }

                if (t1.Namespace.Length < t2.Namespace.Length)
                {
                    return -1;
                }

                return t1.Namespace.CompareTo(t2.Namespace);
            }
        }
    }
}
Main
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace Quartz.Examples
{
    using Common.Logging;
    /// <summary>
    /// This is just a simple job that gets fired off many times by example 2.
    /// </summary>
    /// <author>Bill Kratzer</author>
    /// <author>Marko Lahma (.NET)</author>
    public class SimpleJob : IJob
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(SimpleJob));

        /// <summary>
        /// Called by the <see cref="IScheduler" /> when a
        /// <see cref="ITrigger" /> fires that is associated with
        /// the <see cref="IJob" />.
        /// </summary>
        public virtual void Execute(IJobExecutionContext context)
        {
            
            //这个做业演示简单的打印出做业自己的名称以及正在运行的日期和时间
            JobKey jobKey = context.JobDetail.Key;//做业的名称
            String description=context.JobDetail.Description;//做业的描述
            bool durable=context.JobDetail.Durable;//是否持续着
            log.InfoFormat("SimpleJob says: {0} executing at {1} and Description is {2} and durable is {3}", jobKey, DateTime.Now.ToString("r"), description,durable);
        }
    }
}
SimpleJob
using System.Text;
using Quartz.Impl;
using Common.Logging;
using System.Threading;

namespace Quartz.Examples
{
    
    public class YZRExample:IExample
    {
        #region IExample 成员

        public string Name
        {
            get { return GetType().Name; }
        }

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

            log.Info("------- 开始初始化 -------------------");

            // 使用工厂获得调度实例
            ISchedulerFactory sf = new StdSchedulerFactory();
            IScheduler sched = sf.GetScheduler();

            log.Info("------- 初始化完成 --------");

            log.Info("------- 调度做业 ----------------");
            
            DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(DateTimeOffset.UtcNow.AddMilliseconds(5), 15);
           
            //做业1将会经过startTime指定触发,而且只会运行一次
            IJobDetail job = JobBuilder.Create<SimpleJob>()
                .WithIdentity("job1", "group1")
                .Build();

            ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create()
                                                          .WithIdentity("trigger1", "group1")
                                                          .StartAt(startTime)
                                                          .Build();
            //调度开始运行
            DateTimeOffset? ft = sched.ScheduleJob(job, trigger);
            log.Info(job.Key +
                     " will run at: " + ft +
                     " and repeat: " + trigger.RepeatCount +
                     " times, every " + trigger.RepeatInterval.TotalSeconds + " seconds");
            log.Info("------- Starting Scheduler ----------------");
            sched.Start();
            log.Info("------- Started Scheduler -----------------");
           
            log.Info("------- Waiting five minutes... ------------");
            try
            {
                // wait five minutes to show jobs
                Thread.Sleep(TimeSpan.FromMinutes(5));
                // executing...
            }
            catch (ThreadInterruptedException)
            {
            }

            log.Info("------- Shutting Down ---------------------");

            sched.Shutdown(true);

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

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

        #endregion
    }
}
YZRExample
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Quartz.Examples
{
    /// <summary>
    /// Interface for examples.
    /// </summary>
    /// <author>Marko Lahma (.NET)</author>
    public interface IExample
    {
        string Name
        {
            get;
        }

        void Run();
    }
}
IExample

运行的主要结果以下:

2016-04-23 01:30:04,760 [1] INFO  Quartz.Examples.YZRExample.Run(C:\Users\Admini
strator\Desktop\Quatorz\Quartz.Examples\Quartz.Examples\YZRExample.cs:172)

- ------ Started Scheduler -----------------
2016-04-23 01:30:04,761 [1] INFO  Quartz.Examples.YZRExample.Run(C:\Users\Administrator\Desktop\Quatorz\Quartz.Examples\Quartz.Examples\YZRExample.cs:232)

- ------ Waiting five minutes... ------------
2016-04-23 01:30:15,039 [DefaultQuartzScheduler_Worker-1] INFO  Quartz.Examples.
simpleJob.Execute(C:\Users\Administrator\Desktop\Quatorz\Quartz.Examples\Quartz.
examples\SimpleJob.cs:31) -

SimpleJob says: group1.job1 executing at Sat, 23 Apr
2016 01:30:15 GMT and Description is  and durable is False

从上面的部分打印信息可知,SimpleJob做业被调度了一次,而且是发生在第15秒这个时机。

你可能会疑惑,为何在15秒的时候打印信息?

从头至尾来看一下代码:

 

            // 使用工厂获得调度实例
            ISchedulerFactory sf = new StdSchedulerFactory();
            IScheduler sched = sf.GetScheduler();

 

在定义任何做业被调度以前,都须要使用StdSchedulerFactory()获得一个IScheduler 调度实例,经过这个调度实例来添加做业队列以及相对应的触发器。

DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(DateTimeOffset.UtcNow.AddMilliseconds(5), 15);
DateTimeOffset NextGivenSecondDate(DateTimeOffset? date, int secondBase):
startTime定义的是做业第一次运行的时机,经过DateBuilder.NextGivenSecondDate(DateTimeOffset date,int secondBase);方法获得这个时机,
这个方法具体的意思是指:
            当date为null时,startTime的值将会等于DateTime.Now当前时间
            secondBase是指时间的第一个倍数,0<=secondBase<=59
            好比举个例子:
            在程序运行后的一分钟以后,第一个能整除15的秒数(15s,30s,45s,60s)触发做业,那么这个startTime能够这么声明:
            DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(DateTimeOffset.UtcNow.AddMinutes(1), 15);
            UtcNow值得是时区时间,Now是本地时间(Now本质也是先取时区时间UtcNow再进行转换成本地时间)
           
IJobDetail job = JobBuilder.Create<SimpleJob>()
                .WithIdentity("job1", "group1")
                .Build();
 
IJobDetail 接口定义的是做业类,每个做业类都有一个做业id和组id。
ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create()
                                                          .WithIdentity("trigger1", "group1")
                                                          .StartAt(startTime)
                                                          .Build();

ISimpleTrigger接口定义的是触发器类,每个Tirgger都有一个触发器id和组id。在触发器中指定触发的第一次时机。

            //调度开始运行
            DateTimeOffset? ft = sched.ScheduleJob(job, trigger);
            log.Info(job.Key +
                     " will run at: " + ft +
                     " and repeat: " + trigger.RepeatCount +
                     " times, every " + trigger.RepeatInterval.TotalSeconds + " seconds");

调度实例sched指定做业类和触发器添加到做业队列中。

sched.Start();

须要sched.Start()才会开始调度队列中的做业。

二:如何指定一个做业重复调度的次数以及调度时间间隔呢?

博主认为做业的如何调度是在Tirgger中指定的,而做业自己相关的是定义在Job中,从而可知,做业重复调度的次数以及调度时间间隔这些调度机制是在Tirgger中指定。将上面的tirgger稍微修改一下,代码以下:

 trigger = (ISimpleTrigger)TriggerBuilder.Create()
                                           .WithIdentity("trigger3", "group1")
                                           .StartAt(startTime)
                                           .WithSimpleSchedule(x => x.WithIntervalInSeconds(10).WithRepeatCount(10))//每10秒运行一次,而且重复10次(运行一次重复10次,因此将会运行11次)
                                           .Build();

固然也能够指定无限重复轮询:

 

trigger = (ISimpleTrigger)TriggerBuilder.Create()
                                           .WithIdentity("trigger6", "group1")
                                           .StartAt(startTime)
                                           .WithSimpleSchedule(x => x.WithIntervalInSeconds(40).RepeatForever())
                                           .Build();

 


三:调度实例sched手动加入触发器

调度实例能够手动加入触发器,这样只须要定义做业类:

            //手动加入触发器job8
            
            job = JobBuilder.Create<SimpleJob>()
                .WithIdentity("job8", "group1")
                .StoreDurably()
                .Build();

            sched.AddJob(job, true);
            log.Info("'Manually' triggering job8...");
            sched.TriggerJob(new JobKey("job8", "group1"));

 

 

 四:补充

1.当有多个做业IJobDetail时,能够屡次添加到sched调度实例中,sched调度实例开启以后,实际上会根据优先级来轮询做业。

2.一个做业能够包含多个触发器,好比说,job1和tirgger1添加到sched以外,还能够job1和tirgger2再添加到sched调度队列中。

            //这里再演示一个job拥有多个trigger,使用ForJob("做业对象")来实现 //这一次将只会重复2次每隔10秒
            trigger = (ISimpleTrigger)TriggerBuilder.Create()
                                           .WithIdentity("trigger3", "group2")
                                           .StartAt(startTime)
                                           .WithSimpleSchedule(x => x.WithIntervalInSeconds(10).WithRepeatCount(2))
                                           .ForJob(job)//为做业添加tirgger
                                           .Build();

            ft = sched.ScheduleJob(trigger);

3.能够在定义触发器的时候定义触发时间startTime

            //演示在trigger中指定触发时间
            job = JobBuilder.Create<SimpleJob>()
                .WithIdentity("job5", "group1")
                .Build();

            trigger = (ISimpleTrigger)TriggerBuilder.Create()
                                           .WithIdentity("trigger5", "group1")
                                           .StartAt(DateBuilder.FutureDate(1, IntervalUnit.Minute))
                                           .Build();

            ft = sched.ScheduleJob(job, trigger);

4.触发器中使用RepeatForever能够无限次轮询

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

            trigger = (ISimpleTrigger)TriggerBuilder.Create()
                                           .WithIdentity("trigger6", "group1")
                                           .StartAt(startTime)
                                           .WithSimpleSchedule(x => x.WithIntervalInSeconds(40).RepeatForever())
                                           .Build();

            ft = sched.ScheduleJob(job, trigger);

5.最后强调一下,当job和tirgger都定义好而且添加到调度实例中以后,须要开启调度:

sched.Start();

只有start以后,调度实例中做业队列才会被开始调度。另外,在start()以后,还有继续往调度实例中添加(做业触发器),即便是在start以后添加到队列中去的,只须要将tirgger设置为从新启动,相关的做业仍是会被正常调度。

             // jobs can be re-scheduled...  
            // job 7 will run immediately and repeat 10 times for every second
            log.Info("------- Rescheduling... --------------------");
            trigger = (ISimpleTrigger)TriggerBuilder.Create()
                                           .WithIdentity("trigger7", "group1")
                                           .StartAt(startTime)
                                           .WithSimpleSchedule(x => x.WithIntervalInMinutes(5).WithRepeatCount(20))
                                           .Build();

            ft = sched.RescheduleJob(trigger.Key, trigger);//将触发器指定为该trigger("trigger7", "group1")的做业将会被从新启动

 6.移出执行计划

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

            var tirgger = new TriggerKey("TirggerName", "TirggerGroup");
            sched.PauseTrigger(tirgger);
            var job = new JobKey("jobName","jobGroup");
            sched.PauseJob(job);
            sched.DeleteJob(JobKey.Create("jobName", "jobGroup"));
相关文章
相关标签/搜索