• WebAPI中的定时处理-使用Quartz.Net


    借鉴:

    https://blog.csdn.net/lordwish/article/details/78926252

    在最近的一篇文章中讲到了如何在web API中实现定时处理,采用的是比较原始的Timer定时器,功能简单,无法胜任复杂任务。本次就着重介绍一下定时任务框架Quartz.Net。 
    Quartz.Net来源于Java中的Quartz框架,后来有了.Net版本就加了后缀.Net以示区别。Quartz.Net可以实现诸如定时发送邮件、定时处理数据、定时轮询数据库等计划任务,只需要几句代码,不需要Windows计划任务也能实现诸如“每天早上8:00发送邮件”、“每隔半个小时查询一次库存”之类的目的。

    安装Quartz.Net

    Quartz.Net的安装可以说非常简单,使用NuGet管理器是非常方便的。打开Asp.Net项目,我这里用的是WebApi做的例子(当然用MVC、WPF等也是可以的),打开Nuget管理器,查找Quartz.Net,点击安装。 
    这里写图片描述

    安装完成后会发现项目自动添加了三个类库的引用,分别是Common.Logging、Common.Logging.Core、Quartz,其中Quartz是我们需要用到的核心类库,其余两个是日志相关的类库。

    Quartz.Net使用示例

    这里我将采用上篇的定时发送邮件的示例来说明Quartz.Net,目标是每半个小时发送一封邮件。

    发送邮件方法

            public async Task<int> Auto()
            {
                int num = 0;
                try
                {
                    MailModel model = new MailModel()
                    {
                        ReceiverAddress = "",//收件人地址
                        ReceiverName = "",//收件人姓名
                        Title = "",//邮件标题
                        Content = "",//邮件内容
                        SenderAddress = "",//发件人地址
                        SenderName = "",//发件人姓名
                        SenderPassword = ""//发件人密码
                    };
                    bool result = MailHelper.SendMail(model);
                }
                catch (Exception)
                {
                    num = -1;
                }
                return await Task.FromResult(num);
           }

    创建发送邮件的任务

    Quzrtz中有Job的概念,Job就是我们所讲的任务。

        using Quartz;
        using Quartz.Impl;
        public class TimeJob : IJob
        {
            public void Execute(IJobExecutionContext context)
            {
                //具体的方法
                Auto();
            }
        }

    创建类TimeJob并继承Quzrtz中的接口IJob,实现接口IJob中的方法Execute,在Execute方法中可以创建具体的方法。

    创建任务调度器

        public class JobScheduler
        {
            public static void Start()
            {
                //调度器工厂
                ISchedulerFactory factory = new StdSchedulerFactory();
                //调度器
                IScheduler scheduler = factory.GetScheduler();
                scheduler.GetJobGroupNames();
    
                /*-------------计划任务代码实现------------------*/
                //创建任务
                IJobDetail job = JobBuilder.Create<TimeJob>().Build();
                //创建触发器
                ITrigger trigger = TriggerBuilder.Create().WithIdentity("TimeTrigger", "TimeGroup").WithSimpleSchedule(t => t.WithIntervalInMinutes(30).RepeatForever()).Build();
                //添加任务及触发器至调度器中
                scheduler.ScheduleJob(job, trigger);
                /*-------------计划任务代码实现------------------*/
    
                //启动
                scheduler.Start();
            }
        }

    创建任务调度器类JobScheduler,把上面的定时发送邮件任务TimeJob和触发器添加到任务调度器中。任务Job就是具体要做的事情,触发器Trigger就是任务要执行的时机。可以创建多个Job任务和多个Trigger触发器加入到调度器中。

    启动计划任务

    任务调度器已经完成了,下步要做的就是在程序启动时开启任务调度器了。在项目的Global.asax.cs中进行如下配置

        public class WebApiApplication : System.Web.HttpApplication
        {
    
            protected void Application_Start()
            {
                AreaRegistration.RegisterAllAreas();
    
                //注册定时任务
                Helpers.JobScheduler.Start();
    
                GlobalConfiguration.Configure(WebApiConfig.Register);
                FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                RouteConfig.RegisterRoutes(RouteTable.Routes);
                BundleConfig.RegisterBundles(BundleTable.Bundles);
            }
        }

    使用配置文件实现计划任务

    上面就是一个简单的定时任务示例,但是还有一点不足之处,那就是触发器的配置是在代码中写的,如果我们想由原来的半个小时发一次改成一个小时发一次,就需要改代码、编译、发布,显然太麻烦,有没有更好的方式呢?幸运的是Quartz.Net可以通过XML配置文件实现定时任务。仍然是上面发邮件的例子,我们使用配置文件来实现。

    修改Web.config文件

    修改项目配置文件Web.config,在configSections节点下添加子节点,对应的添加Quartz的基本配置。在最后一行的“key=”quartz.plugin.xml.fileNames” value=”~/quartz_jobs.xml” ”,表示Quertz的任务调度计划。

      <configSections>
        <!--Quartz-->
        <section name="quartz" type="System.Configuration.NameValueSectionHandler"/>
      </configSections>
    
      <!--Quartz配置-->
      <quartz>
        <add key="quartz.scheduler.instanceName" value="ExampleDefaultQuartzScheduler"/>
        <add key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz"/>
        <add key="quartz.threadPool.threadCount" value="10"/>
        <add key="quartz.threadPool.threadPriority" value="2"/>
        <add key="quartz.jobStore.misfireThreshold" value="60000"/>
        <add key="quartz.jobStore.type" value="Quartz.Simpl.RAMJobStore, Quartz"/>
        <!--******************************Plugin配置*********************************************-->
        <add key="quartz.plugin.xml.type" value="Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz" />
        <add key="quartz.plugin.xml.fileNames" value="~/quartz_jobs.xml"/>
      </quartz>

    添加quzrtz_jobs.xml

    对应上面提到的配置文件中文件路径“key=”quartz.plugin.xml.fileNames” value=”~/quartz_jobs.xml” ”,在项目目录下添加文件quartz_jobs.xml,项目启动是会从此文件中读取任务计划来执行,具体内容如下:

    <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>
          <!--任务名称【必填】:同一group中多个job的name名不能相同-->
          <name>TimeJob</name>
          <!--任务所属分组【选填】-->
          <group>Timer</group>
          <!--任务描述【选填】-->
          <description>定时任务</description>
          <!--任务类型【必填】:实现IJob接口完整命名空间的类名,程序集名-->
          <job-type>WebAPI.Helpers.TimeJob, WebAPI</job-type>
          <durable>true</durable>
          <recover>false</recover>
        </job>
    
        <!--触发器,可添加多个-->
        <trigger>
          <!--simple:简单触发器类型,cron:复杂触发器类型【推荐】-->
          <cron>
            <!--触发器名称【必填】:同一group中多个trigger的name不能相同-->
            <name>TimeTrigger</name>
            <!--触发器组【选填】-->
            <group>Timer</group>
            <!--触发器描述【选填】-->
            <description>每隔半小时推送未处理报警信息</description>
            <!--要调度的任务名称【必填】:必须和对应job节点中的name相同-->
            <job-name>TimeJob</job-name>
            <!--要调度的任务的所属分组【选填】:必须和对应job节点中的group相同-->
            <job-group>Timer</job-group>
            <cron-expression>0 */30 * * * ?</cron-expression>
          </cron>
    
        </trigger>
        <!--结束一个调度-->
      </schedule>
    </job-scheduling-data>

    修改调度器类

    配置文件修改完成后,再对调度器类进行相应修改,只需要将创建任务、触发器的代码去掉即可,如下:

        public class JobScheduler
        {
            public static void Start()
            {
                //调度器工厂
                ISchedulerFactory factory = new StdSchedulerFactory();
                //调度器
                IScheduler scheduler = factory.GetScheduler();
                scheduler.GetJobGroupNames();
                //启动
                scheduler.Start();
            }
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Quartz.Net使用进阶

    上面就是我们使用Quartz实现的简单定时任务,如果要实现更复杂的任务调度,强烈推荐使用cron复杂任务触发器。cron复杂任务触发器支持使用cron表达式自定义任务调度,理解了cron表达式的结构和用法,实现各种定制性的任务调度就不会有太大问题了。cron表达式由“秒分时日月星期年”共7段构成,其中“年”是可选的。Quartz官方文档提供的cron表达式的相关说明。

    cron表达式说明

    字段名是否必填取值范围允许特殊字符
    必填 0-59 ,-*/
    必填 0-59 ,-*/
    必填 0-23 ,-*/
    必填 1-31 ,-*?/LW
    必填 1-12或JAN-DEC ,-*/
    星期 必填 1-7或SUN-SAT ,-*?/LW
    非必填 空,1970-2099 ,-*/

    cron特殊字符说明

    特殊字符说明
    * 表示“每”,比如每小时、每分钟、每日、每年
    ? 表示不指定具体的值,只能出现在日、星期中
    - 表示范围,比如时字段中10-12表示10点、11点、12点
    , 表示列举,比如“MON,WED,FRI”表示周一、周三和周五
    / 表示增量,比如在秒字段中“0/15”表示从0秒开始每次增加15秒,也就是15、30、45秒
    L 表示最后的,只能出现在日、星期字段中,表示一个月的最后一天、一个星期的最后一天
    W 表示工作日,指距离给定日期最近的工作日
    # 表示一个月的第几个星期几,比如“6#3”表示每个月的第三个周五

    cron表达式示例

    表达式含义
    0 0 12 * * ? 每天12点
    0 15 10 ? * * 每天10:15
    0 15 10 * * ? 每天10:15
    0 15 10 * * ? * 每天10:15
    0 15 10 * * ? 2005年每天10:15
    0 * 14 * * ? 每天14:00到14:59期间的每一分钟
    0 0/5 14 * * ? 每天14:00到14:55期间的每5分钟
    0 0/5 14,18 * * ? 每天14:00到14:55和18:00到18:55期间的每5分钟
    0 0-5 14 * * ? 每天14:00到14:05期间的每一分钟
    0 10,44 14 ? 3 WED 每年三月的星期三的14:10和14:44
    0 15 10 ? * MON-FRI 周一到周五的10:15
    0 15 10 15 * ? 每月15日的10:15
    0 15 10 L * ? 每月最后一天的10:15
    0 15 10 L-2 * ? 每月倒数第二天的10:15
    0 15 10 ? * 6L 每月最后一个周五的10:15
    0 15 10 ? * 6L 2002-2005 从2002年至2005年期间每月最后一个周五的10:15
    0 15 10 ? * 6#3 每月第三个周五的10:15
    0 0 12 1/5 * ? 从每月第一天开始,每隔5天的12:00
    0 11 11 11 11 ? 每年11月11日11:11

    Quartz定时任务日志

    通过日志记录定时计划的执行情况是很有用的,Quartz自身提供的Common.Logging来记录日志,我们也可以结合Log4net或者Nlog来实现定时任务的运行日志,当然也可以保存到数据库中,具体方法本文不再详细说明。


    以上就是关于Quartz.Net开源计划调度框架的简单说明,更详细的内容请参考Quartz的官网

    Quartz.Net

  • 相关阅读:
    Linux常用命令
    Linux静态函数库与动态函数库
    解决MySQL5.7的表无法插入中文的问题
    MySQL与postgreSQL在left join查询时的区别
    《刻意练习》读书笔记
    在Golang中实现与Python装饰器类似功能的方法
    项目中使用进程内缓存的一些经验及注意事项
    Golang中使用recover捕获panic的操作及遇到的一个坑
    Python与Golang中给列表中字典按照某个key排序的实现
    浅谈Python与Golang中的“延迟绑定机制”
  • 原文地址:https://www.cnblogs.com/pangzili/p/8717040.html
Copyright © 2020-2023  润新知