zoukankan      html  css  js  c++  java
  • Quartz.net开源作业调度框架使用详解

    原文 : Quartz.net开源作业调度框架使用详解

     

    前言

    quartz.net作业调度框架是伟大组织OpenSymphony开发的quartz scheduler项目的.net延伸移植版本。支持 cron-like表达式,集群,数据库。功能性能强大更不用说。

    下载项目文档官网:http://www.quartz-scheduler.net/

    项目中需引用:Common.Logging.dll , Common.Logging.Core.dll , Quartz.dll 

    下面给大家分解下我最近做的关于计划调度的一个小项目,来辅助理解quartz.net的功能和常用方法。

    quartz.net的简单用法 -入门

    如果你是quartz.net的使用新手,控制台入门这里,建议跟着做下,那么10分钟搞懂quartz.net也是 so easy 的事.

    1.创建一个每隔3秒钟执行一次的计划调度

    复制代码
    public class RunMain
        {
            static void Main(string[] args)
            {
                Console.WriteLine(DateTime.Now.ToString("r"));
                //1.首先创建一个作业调度池
                ISchedulerFactory schedf = new StdSchedulerFactory();
                IScheduler sched = schedf.GetScheduler();
                //2.创建出来一个具体的作业
                IJobDetail job = JobBuilder.Create<JobDemo>().Build();           
                //3.创建并配置一个触发器
                ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().WithSimpleSchedule(x=>x.WithIntervalInSeconds(3).WithRepeatCount(int.MaxValue)).Build();
                //4.加入作业调度池中
                sched.ScheduleJob(job, trigger);
                //5.开始运行
                sched.Start();
                Console.ReadKey();
            }
        }
        public class JobDemo : IJob
        {
            /// <summary>
            /// 这里是作业调度每次定时执行方法
            /// </summary>
            /// <param name="context"></param>
            public void Execute(IJobExecutionContext context)
            {
                Console.WriteLine(DateTime.Now.ToString("r"));
            }
        }
    复制代码

    Note:1、记下作业调度创建的顺序。2、上述代码执行结果是,每三秒执行一次JobDemo中的Execute,如果程序不停止,无休无止执行到天荒地老,呵呵,扯下蛋啊。

    2.改进(丰富调度计划):上一个作业,我想让他每三秒执行一次,一共执行100次,开始执行时间设定在当前时间,结束时间我设定在2小时后,不过100次执行完没2小时候都不再执行。

    复制代码
        public class RunMain
        {
            static void Main(string[] args)
            {
                Console.WriteLine(DateTime.Now.ToString("r"));
                //首先创建一个作业调度池
                ISchedulerFactory schedf = new StdSchedulerFactory();
                IScheduler sched = schedf.GetScheduler();
                //创建出来一个具体的作业
                IJobDetail job = JobBuilder.Create<JobDemo>().Build();
                //NextGivenSecondDate:如果第一个参数为null则表名当前时间往后推迟2秒的时间点。
                DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddSeconds(1), 2);
                DateTimeOffset endTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddHours(2), 3);
                //创建并配置一个触发器
                ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().StartAt(startTime).EndAt(endTime)                
                                            .WithSimpleSchedule(x=>x.WithIntervalInSeconds(3).WithRepeatCount(100))
                                            .Build();
                //加入作业调度池中
                sched.ScheduleJob(job, trigger);
                //开始运行
                sched.Start();
                Console.ReadKey();
            }
        }
        public class JobDemo : IJob
        {
            /// <summary>
            /// 这里是作业调度每次定时执行方法
            /// </summary>
            /// <param name="context"></param>
            public void Execute(IJobExecutionContext context)
            {
                Console.WriteLine(DateTime.Now.ToString("r"));
            }
        }
    复制代码
    View Code

    3.继续改进(cron-like使用):前两个作业调度都太简单,如果我想在每小时的第10,20,25,26,33,54分钟,每分钟的第1,10,14秒执行一次。那么上面显然是不能满足的。这是我就把cron-like表达式引入进来,以实现各种时间纬度的调用。

    复制代码
     public class RunMain
        {
            static void Main(string[] args)
            {
                Console.WriteLine(DateTime.Now.ToString("r"));
                //首先创建一个作业调度池
                ISchedulerFactory schedf = new StdSchedulerFactory();
                IScheduler sched = schedf.GetScheduler();
                //创建出来一个具体的作业
                IJobDetail job = JobBuilder.Create<JobDemo>().Build();
                //NextGivenSecondDate:如果第一个参数为null则表名当前时间往后推迟2秒的时间点。
                DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddSeconds(1), 2);
                DateTimeOffset endTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddYears(2), 3);
                //创建并配置一个触发器
                ICronTrigger trigger = (ICronTrigger)TriggerBuilder.Create().StartAt(startTime).EndAt(endTime)
                                            .WithCronSchedule("1,10,14 10,20,25,26,33,54 * * * ? ")
                                            .Build();
                //加入作业调度池中
                sched.ScheduleJob(job, trigger);
                //开始运行
                sched.Start();
                //挂起2天
                Thread.Sleep(TimeSpan.FromDays(2));
                //2天后关闭作业调度,将不在执行
                sched.Shutdown();
                Console.ReadKey();
            }
        }
        public class JobDemo : IJob
        {
            /// <summary>
            /// 这里是作业调度每次定时执行方法
            /// </summary>
            /// <param name="context"></param>
            public void Execute(IJobExecutionContext context)
            {
                Console.WriteLine(DateTime.Now.ToString("r"));
            }
        }
    复制代码

    基于Quartz.net的作业调度项目详解

    最终效果如开篇的第一个图所示。

    下面主要说说,作业调度的中怎么定位到具体的作业调度,并给作业调度分组,命名,添加,启动,停止。

    首先展示下表结构,项目中我叫作业调度为任务调度。

    1、新增作业调度。

    复制代码
     /// <summary>
            /// 任务计划
            /// </summary>
            public static IScheduler scheduler = null;
            public static IScheduler GetScheduler()
            {
                if (scheduler != null)
                {
                    return scheduler;
                }
                else
                {
                    ISchedulerFactory schedf = new StdSchedulerFactory();
                    IScheduler sched = schedf.GetScheduler();
                    return sched;
                }
            }
     /// <summary>
            /// 添加任务计划
            /// </summary>
            /// <returns></returns>
            public bool AddScheduleJob(WJ_ScheduleEntity m)
            {
                try
                {
                    if (m != null)
                    {
                        if (m.StarRunTime == null)
                        {
                            m.StarRunTime = DateTime.Now;
                        }
                        DateTimeOffset starRunTime = DateBuilder.NextGivenSecondDate(m.StarRunTime, 1);
                        if (m.EndRunTime == null)
                        {
                            m.EndRunTime = DateTime.MaxValue.AddDays(-1);
                        }
                        DateTimeOffset endRunTime = DateBuilder.NextGivenSecondDate(m.EndRunTime, 1);
                        scheduler = GetScheduler();
                        IJobDetail job = JobBuilder.Create<HttpJob>()
                          .WithIdentity(m.JobName, m.JobGroup)
                          .Build();
                        ICronTrigger trigger = (ICronTrigger)TriggerBuilder.Create()
                                                     .StartAt(starRunTime)
                                                     .EndAt(endRunTime)
                                                     .WithIdentity(m.JobName, m.JobGroup)
                                                     .WithCronSchedule(m.CronStr)
                                                     .Build();
                        scheduler.ScheduleJob(job, trigger);
                        scheduler.Start();
                        StopScheduleJob(m.JobGroup, m.JobName);
                        return true;
                    }
                    return false;
                }
                catch (Exception ex)
                {
                    //DoApplication.WriteLogFile(ex.Message + "
    " + ex.StackTrace);
                    return false;
                }
            }
    复制代码

    Note:1.这里作业调度执行的函数如下。2.上面的WithIdentity(m.JobName, m.JobGroup) ,是给作业调度加入组,和名称,方便我们针对哪一个作业计划,进行启动停止等操作。

    复制代码
     public class HttpJob : IJob
        {
            public void Execute(IJobExecutionContext context)
            {
                ThreadPool.QueueUserWorkItem(delegate(Object o)
                {
                    try
                    {
                        //DoApplication.WriteLogFile(context.JobDetail.Key.Group + "---" + context.JobDetail.Key.Name + "---" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "---" + context.NextFireTimeUtc.Value.DateTime.AddHours(8).ToString("yyyy-MM-dd HH:mm:ss"));
                        var sm = new WJ_ScheduleManage().GetScheduleModel(new WJ_ScheduleEntity() { JobGroup = context.JobDetail.Key.Group, JobName = context.JobDetail.Key.Name });
                        new WJ_ScheduleManage().UpdateScheduleRunStatus(new WJ_ScheduleEntity() { JobGroup = context.JobDetail.Key.Group, JobName = context.JobDetail.Key.Name,RunStatus=(int)ADJ.Job.Entity.EnumType.JobRunStatus.执行中 });
                        ESBRequest req = new ESBRequest(sm.ServiceCode, sm.ApiCode);
                        DataResult result = req.Request();
                        new WJ_ScheduleManage().UpdateScheduleRunStatus(new WJ_ScheduleEntity() { JobGroup = context.JobDetail.Key.Group, JobName = context.JobDetail.Key.Name, RunStatus = (int)ADJ.Job.Entity.EnumType.JobRunStatus.待运行 });
                        if (result.Code == 1)
                        {
                            #region 加入执行明细
                            WJ_ScheduleDetailsEntity dm = new WJ_ScheduleDetailsEntity();
                            dm.ActionDescribe = "执行完成:" + result.Message ;
                            dm.ActionStep = (int)ADJ.Job.Entity.EnumType.JobStep.执行完成;
                            dm.CreateTime = DateTime.Now;
                            dm.JobGroup = context.JobDetail.Key.Group;
                            dm.JobName = context.JobDetail.Key.Name;
                            dm.IsSuccess = 1;
                            new WJ_ScheduleManage().AddScheduleDetails(dm);
                            #endregion
                        }
                        else
                        {
                            #region 加入执行明细
                            WJ_ScheduleDetailsEntity dm = new WJ_ScheduleDetailsEntity();
                            dm.ActionDescribe = "执行任务计划中,执行计划过程出错."+result.Message;
                            dm.ActionStep = (int)ADJ.Job.Entity.EnumType.JobStep.执行任务计划中;
                            dm.CreateTime = DateTime.Now;
                            dm.JobGroup = context.JobDetail.Key.Group;
                            dm.JobName = context.JobDetail.Key.Name;
                            dm.IsSuccess = 0;
                            new WJ_ScheduleManage().AddScheduleDetails(dm);
                            #endregion
                        }
                        new WJ_ScheduleManage().UpdateScheduleNextTime(new WJ_ScheduleEntity() { JobGroup = context.JobDetail.Key.Group, JobName = context.JobDetail.Key.Name, NextTime = context.NextFireTimeUtc.Value.DateTime.AddHours(8) });
                    }
                    catch (Exception ex)
                    {
                        #region 加入执行明细
                        WJ_ScheduleDetailsEntity dm = new WJ_ScheduleDetailsEntity();
                        dm.ActionDescribe = "执行任务计划中,执行计划过程出错:" + ex.Message + "/r/n" + ex.StackTrace;
                        dm.ActionStep = (int)ADJ.Job.Entity.EnumType.JobStep.执行任务计划中;
                        dm.CreateTime = DateTime.Now;
                        dm.JobGroup = context.JobDetail.Key.Group;
                        dm.JobName = context.JobDetail.Key.Name;
                        dm.IsSuccess = 0;
                        new WJ_ScheduleManage().AddScheduleDetails(dm);
                        #endregion
                        DoApplication.WriteLogFile(ex.Message + "
    " + ex.StackTrace);
                    }
                });
            }
        }
    复制代码
    View Code

    note:这里执行的Execute方法参数IJobExecutionContext 中,会自动把作业调度的详细信息带过来,作业名称,作业组名,作业下次执行时间,作业执行时间等等,这里的内容也是至关重要的,比如根据作业组,作业名称我们可以从数据库找到相应的作业调度详细,更新操作数据库。

    2、针对某个作业计划进行停止,启动。

    复制代码
     /// <summary>
            /// 暂停指定任务计划
            /// </summary>
            /// <returns></returns>
            public JsonResult StopScheduleJob(string jobGroup, string jobName)
            {
                try
                {
                    scheduler = GetScheduler();                
                    scheduler.PauseJob(new JobKey(jobName, jobGroup));
                    new WJ_ScheduleManage().UpdateScheduleStatus(new WJ_ScheduleEntity() { JobName = jobName, JobGroup = jobGroup, Status = (int)ADJ.Job.Entity.EnumType.JobStatus.已停止 });               
                    return Json(new StatusView() { Status = 0, Msg = "停止任务计划成功!" }, JsonRequestBehavior.AllowGet);
                }
                catch (Exception ex)
                {               
                    DoApplication.WriteLogFile(ex.Message + "/r/n" + ex.StackTrace);
                    return Json(new StatusView() { Status = -1, Msg = "停止任务将计划失败!" }, JsonRequestBehavior.AllowGet);
                }
            }
            /// <summary>
            /// 开启指定的任务计划
            /// </summary>
            /// <returns></returns>
            public JsonResult RunScheduleJob(string jobGroup, string jobName)
            {
                try
                {
                    var sm = new WJ_ScheduleManage().GetScheduleModel(new WJ_ScheduleEntity() { JobName = jobName, JobGroup = jobGroup });
                    AddScheduleJob(sm);
                    sm.Status = (int)ADJ.Job.Entity.EnumType.JobStatus.已启用;
                    new WJ_ScheduleManage().UpdateScheduleStatus(sm);
                    scheduler = GetScheduler();
                    scheduler.ResumeJob(new JobKey(jobName, jobGroup));
                    return Json(new StatusView() { Status = 0, Msg = "启动成功!" }, JsonRequestBehavior.AllowGet);
                }
                catch (Exception ex)
                {
                  
                    DoApplication.WriteLogFile(ex.Message + "/r/n" + ex.StackTrace);
                    return Json(new StatusView() { Status = -1, Msg = "启动失败!" }, JsonRequestBehavior.AllowGet);
                }
            }
    复制代码

    最后注意:

    1、这个项目完全使用啦cron-like表达式实现触发器配置,如果你对cron不了解,那么我上篇中有针对cron做介绍讲解,如果你对cron了解而没有一个合适的生成工具,那么入左上方2个群,找我。

    2、这个项目部署在IIS中,那么就要设置应用程序池的回收机制为,永不回收,配置下,如果不会配置,入左上方2个群,找我。

  • 相关阅读:
    Effective C++笔记_条款25考虑写出一个不抛出异常的swap函数
    SilverLight小游戏
    可分片数据持久层ShardingPL使用说明
    r.a.d controls 学习笔记 - radcombobox + RadWindowManager 组成的参照控件
    用 .Net Remoting 技术实现“定向广播”
    Silverlight中的资源文件
    一个丑陋的对Silverlight中的Grid无CellPadding的解决方案
    几个小问题
    .Net Remoting 排错笔记:An existing connection was forcibly closed by the remote host
    .Net Remoting 排错笔记:The constructor to deserialize an object of type 'xxx.xxxx.xxxxx' was not found.
  • 原文地址:https://www.cnblogs.com/zhang1f/p/11953609.html
Copyright © 2011-2022 走看看