ABP module-zero +AdminLTE+Bootstrap Table+jQuery权限管理系统第十七节--Quartz与ABP框架Abp.Quar

ABP+AdminLTE+Bootstrap Table权限管理系统一期 Github:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMShtml

Quartz简介

Quartz.NET是一个开源的做业调度框架,是 OpenSymphonyQuartz API 的.NET移植,它用C#写成,可用于winformasp.net应用中。它提供了巨大的灵活性而不牺牲简单性。你可以用它来为执行一个做业而建立简单的或复杂的调度。它有不少特征,如:数据库支持,集群,插件,支持cron-like表达式等等。很是适合在平时的工做中,定时轮询数据库同步,定时邮件通知,定时处理数据等.git

参考

对Quartz.NET不熟悉的能够先看下 官方学习文档:www.quartz-scheduler.net/documentati… 使用实例介绍:www.quartz-scheduler.net/documentati… 官方的源代码下载:sourceforge.net/projects/qu…github

特性 它一些很好的特性:数据库

  1. 支持集群,做业分组,做业远程管理。
  2. 自定义精细的时间触发器,使用简单,做业和触发分离。
  3. 数据库支持,能够寄宿Windows服务,WebSitewinform等。

Quartz框架的一些基础概念解释:bash

名称 描述
Scheduler 做业调度器。
 IJob 做业接口,继承并实现Execute, 编写执行的具体做业逻辑。
JobBuilder 根据设置,生成一个详细做业信息(JobDetail)。
TriggerBuilder 根据规则,生产对应的Trig

##实战框架

  • Web.config配置

基础概念我就懒得讲了,你也懒得听了,直接上代码吧。 首先配置一下Web.config,其实这步无关紧要,能够直接跳过,只是为了配置一些常量,获取固定的时间,可是不是必要的。asp.net

<sectionGroup name="JobList">
      <section name="Job" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
    </sectionGroup>
复制代码
<JobList>
    <Job>
      <!--这里是一个任务节点-->
      <add key="Url" value="http://www.baidu.com" />
      <!--须要访问的Url-->
      <add key="Hour" value="10" />
      <!--开始时间小时-->
      <!--开始时间小时,注意:这里的小时为0-23,若是是1点的话就是1,而不是01-->
      <add key="Minute" value="30" />
      <!--开始时间分钟-->
      <!--开始时间分钟,注意:同上0-59-->
    </Job>
  </JobList>
复制代码
  • 建立service 建立ISystemSchedulerService以及SystemSchedulerService,代码上面都有详细的注释,我就不重复了。 接口:
public  interface ISystemSchedulerService: IApplicationService
    {
        void StartScheduler();
    }
复制代码

service: SystemSchedulerServiceasync

public class SystemSchedulerService : ISystemSchedulerService
    {
        private IScheduler _scheduler;
        public ILogger _Logger { get; set; }
        public SystemSchedulerService()
        {
            _Logger = NullLogger.Instance;
        }

        public void StopScheduler()
        {
            _scheduler.Shutdown();
        }

        public void StartScheduler()
        {
            try
            {

                //这里读取配置文件中的任务开始时间
                int hour = int.Parse(((NameValueCollection)ConfigurationManager.GetSection("JobList/Job"))["Hour"]);
                int minute = int.Parse(((NameValueCollection)ConfigurationManager.GetSection("JobList/Job"))["Minute"]);


                ISchedulerFactory schedulerFactory = new StdSchedulerFactory();//内存调度
                _scheduler = schedulerFactory.GetScheduler();

                //建立一个Job来执行特定的任务
                IJobDetail myLogJob = new JobDetailImpl("myLogJob", typeof(MyLogJob));
                //建立并定义触发器的规则(天天执行一次时间为:时:分)
               ITrigger trigger =
                   TriggerBuilder.Create()
                       .WithDailyTimeIntervalSchedule(
                          a => a.WithIntervalInHours(24).OnEveryDay().StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(hour, minute))).Build();
  
                _scheduler.Clear();
                //将建立好的任务和触发规则加入到Quartz中
                _scheduler.ScheduleJob(myLogJob, trigger);
                //开始
                _scheduler.Start();

            }
            catch (Exception ex)
            {
                _Logger.Info(ex.Message);
            }
        }

    }
复制代码

Quartz API

Quartz API的关键接口和类是:ide

  • IScheduler - 与调度程序交互的主要API。 -IJob- 您但愿由调度程序执行的组件实现的接口。
  • IJobDetail - 用于定义做业的实例。
  • ITrigger- 定义执行给定Job的时间表的组件。
  • JobBuilder - 用于定义/构建obDetail实例,它定义了Jobs的实例。
  • TriggerBuilder- 用于定义/构建触发器实例。

一个调度程序的生命周期是由它为界的创做,经过SchedulerFactory和其有关方法的调用。一旦建立了IScheduler接口,就可使用添加,删除和列出做业和触发器,并执行其余与调度相关的操做(例如暂停触发器)。可是,调度程序不会实际上对任何触发器(执行做业)执行操做,直到使用Start()方法启动它。学习

构建做业定义的代码块使用使用流畅接口的JobBuilder建立产品IJobDetail。一样,构建触发器的代码块使用TriggerBuilder流畅的接口和特定于触发器类型的扩展方法。可能的时间延长方法是:

  • WithCalendarIntervalSchedule
  • WithCronSchedule
  • WithDailyTimeIntervalSchedule
  • WithSimpleSchedule
    image.png

示例中的ITrigger其实能够不读取配置信息的。这就是我说的不用配置Web.config也能够。效果以下,每隔10秒执行一次。

ITrigger trigger =
                TriggerBuilder.Create()
                    .WithDailyTimeIntervalSchedule(
                        a => a.WithIntervalInSeconds(10)).Build();
复制代码

工做和触发器

代码:

public class MyLogJob : JobBase, ITransientDependency
    {
        public ILogger _Logger { get; set; }
        public MyLogJob()
        {
            _Logger = NullLogger.Instance;

        }

        public override void Execute(IJobExecutionContext context)
        {
            try
            {
                _Logger.Info("QuartzJob 任务开始运行");

                for (int i = 0; i < 10; i++)
                {
                    _Logger.InfoFormat("QuartzJob 正在运行{0}", i);
                }

                _Logger.Info("QuartzJob任务运行结束");
            }
            catch (Exception ex)
            {
                _Logger.Error("运行异常:"+ex.Message, ex);
            }

        }
    }
复制代码

看成业的触发器触发,Execute(..)方法由调度程序的工做线程之一调用。传递给此方法的JobExecutionContext对象为做业实例提供有关其“运行时”环境的信息 ( 调度程序执行的逻辑),触发执行的触发器的逻辑。 JobDetail对象是在Job添加到调度器时由Quartz.NET客户端建立的。它包含Job的各类属性设置,以及一个JobDataMap,它能够用来存储做业类的给定实例的状态信息 触发器对象用于触发做业的执行(或“触发”)。当你想安排一个工做,你实例化一个触发器并“调整”它的属性来提供你想要的调度。触发器也可能有一个与它们相关的JobDataMap- 这对于传递参数到一个特定于触发器的触发的Job是颇有用的。Quartz提供了一些不一样的触发器类型,但最经常使用的类型是SimpleTrigger(接口ISimpleTrigger)和CronTrigger(接口ICronTrigger)。 若是您须要“一次性”执行(在某个特定时间只执行一项做业),或者您须要在给定时间开始工做,而且重复执行N次,SimpleTrigger会很方便的T之间执行。若是您但愿基于相似日历的时间表(例如“每一个星期五,中午”或“每月的第10天的10:15”)触发,则CronTrigger很是有用。

public class UserInfoController : ABPCMSControllerBase
    {

        private readonly ISystemSchedulerService _iSystemSchedulerService;
        public UserInfoController(ISystemSchedulerService iSystemSchedulerService)
        {

            _iSystemSchedulerService = iSystemSchedulerService;
        }

        [HttpGet]
        [DontWrapResult]
        public async Task<ActionResult> GetUserInfo()
        {
            _iSystemSchedulerService.StartScheduler();
        }
}
复制代码

而后咱们在前台控制器里面调用ISystemSchedulerServiceStartScheduler()方法。而后运行项目。 而后咱们打开日志Web\App_Data\Logs\Logs.txt,看下效果:

image.png
每隔十秒钟执行一次。

Abp.Quartz

ABP有內建的持久化后台job队列和后台worker系统。若是对于后台workers你有更高级的计划安排需求,Quartz会是一个更好的选择。对于持久化后台job队列,Hangfire也是一个好的选择。 ABP中Quartz应用其实蛮简单的。

  1. 首先Abp.Quartz nuget包
  2. 而后加上引入到项目中。
[DependsOn(
     typeof(AbpQuartzModule)
        )]
  public class ABPCMSWebModule : AbpModule
    { 
     }
复制代码
  1. 建立Jobs  这里咱们就用上面例子中的job,固然建立一个新job,你能够实现QuartzIJob接口,或者继承JobBase类(定义在Abp.Quartz包),这个类包含一些帮助属性和方法(例如日志和本地化)。
public class MyLogJob : JobBase, ITransientDependency
{
    public override void Execute(IJobExecutionContext context)
    {
        Logger.Info("Executed MyLogJob :)");
    }
}
复制代码

4.建立调度做业 IQuartzScheduleJobManager接口被用来建立调度做业。你能够在类中注入该接口(或者你能够在你的模块的PostInitialize方法中解析和使用它)来调度做业。这里咱们把以前建立的MyLogJob引用进来。 效果以下:

public async Task<ActionResult> ScheduleJob()
        {
            await _jobManager.ScheduleAsync<MyLogJob>(
                job =>
                {
                    job.WithIdentity("MyLogJobIdentity", "MyGroup")
                        .WithDescription("A job to simply write logs.");
                },
                trigger =>
                {
                    trigger.StartNow()
                        .WithSimpleSchedule(schedule =>
                        {
                            schedule.RepeatForever()
                                .WithIntervalInSeconds(5)
                                .Build();
                        });
                });
            _jobManager.Start();
            return Content("OK, scheduled!");
        }
复制代码

效果同样。

image.png
通过上面四步,就完成Abp.Quartz运用,是挺简单的。

扩展

####SimpleTrigger

说一下SimpleTriggerWithCronSchedule()这里有三种方式,一种就是上面说到的Web.config配置,一种是WithCronSchedule设置时间参数。还有一种是WithCronSchedule("") 拥有强大的Cron时间表达式。

SimpleTrigger应知足你的日程安排需求,若是你须要在某个特定时刻及时执行一次做业,或者在特定时间执行一次,而后在特定时间间隔重复执行。若是你想让触发器在2018年1月13日上午11点23分54秒执行,而后再执行5次,每10秒执行一次。

经过这个描述,你可能不会以为奇怪的是,SimpleTrigger的属性包括:开始时间和结束时间,重复计数和重复间隔。全部这些属性都与您所指望的彻底相同,只有一些与结束时间属性相关的特殊注释。

SimpleTrigger实例是使用TriggerBuilder(用于触发器的主属性)和WithSimpleSchedule扩展方法(用于SimpleTrigger特有的属性)构建的。

在特定的时刻创建一个触发器,不要重复:

// trigger builder creates simple trigger by default, actually an ITrigger is returned
ISimpleTrigger trigger = (ISimpleTrigger) TriggerBuilder.Create()
    .WithIdentity("trigger1", "group1")
    .StartAt(myStartTime) // some Date 
    .ForJob("job1", "group1") // identify job with name, group strings
    .Build();
复制代码

创建一个特定时刻的触发器,而后每十秒钟重复十次:

trigger = TriggerBuilder.Create()
    .WithIdentity("trigger3", "group1")
    .StartAt(myTimeToStartFiring) // if a start time is not given (if this line were omitted), "now" is implied
    .WithSimpleSchedule(x => x
        .WithIntervalInSeconds(10)
        .WithRepeatCount(10)) // note that 10 repeats will give a total of 11 firings
    .ForJob(myJob) // identify job with handle to its JobDetail itself                   
    .Build();
复制代码

创建一个触发器,将在将来五分钟内触发一次:

trigger = (ISimpleTrigger) TriggerBuilder.Create()
    .WithIdentity("trigger5", "group1")
    .StartAt(DateBuilder.FutureDate(5, IntervalUnit.Minute)) // use DateBuilder to create a date in the future
    .ForJob(myJobKey) // identify job with its JobKey
    .Build();
复制代码

创建一个触发器,如今会触发,而后每隔五分钟重复一次,直到22:00:

trigger = TriggerBuilder.Create()
    .WithIdentity("trigger7", "group1")
    .WithSimpleSchedule(x => x
        .WithIntervalInMinutes(5)
        .RepeatForever())
    .EndAt(DateBuilder.DateOf(22, 0, 0))
    .Build();
复制代码

创建一个触发器,将在下一个小时的顶部执行,而后每2小时重复一次:

trigger = TriggerBuilder.Create()
    .WithIdentity("trigger8") // because group is not specified, "trigger8" will be in the default group
    .StartAt(DateBuilder.EvenHourDate(null)) // get the next even-hour (minutes and seconds zero ("00:00"))
    .WithSimpleSchedule(x => x
        .WithIntervalInHours(2)
        .RepeatForever())
    // note that in this example, 'forJob(..)' is not called 
    //  - which is valid if the trigger is passed to the scheduler along with the job  
    .Build();

await scheduler.scheduleJob(trigger, job);
复制代码

另一些经常使用的中止做业的指令常量

  • MisfireInstruction.IgnoreMisfirePolicy
  • MisfirePolicy.SimpleTrigger.FireNow
  • MisfirePolicy.SimpleTrigger.RescheduleNowWithExistingRepeatCount
  • MisfirePolicy.SimpleTrigger.RescheduleNowWithRemainingRepeatCount
  • MisfirePolicy.SimpleTrigger.RescheduleNextWithRemainingCount
  • MisfirePolicy.SimpleTrigger.RescheduleNextWithExistingCount

在构建SimpleTriggers时,能够将简单的时间表(经过SimpleSchedulerBuilder)指定为中止做业指令:

trigger = TriggerBuilder.Create()
    .WithIdentity("trigger7", "group1")
    .WithSimpleSchedule(x => x
        .WithIntervalInMinutes(5)
        .RepeatForever()
        .WithMisfireHandlingInstructionNextWithExistingCount())
    .Build();
复制代码

Cron时间表达式。

Cron-Expressions用于配置CronTrigger的实例。Cron-Expressions是由七个子表达式组成的字符串,它们描述了计划的各个细节。这些子表达式用空格分隔,表示:

  • Seconds
  • Minutes
  • Hours
  • Day-of-Month
  • Month
  • Day-of-Week
  • Year (optional field)

示例Cron表达式 下面是一些表达式及其含义的例子 - 你能够在CronTrigger的API文档中找到更多的例子 CronTrigger示例1 - 建立一个触发器的表达式,每5分钟触发一次 "0 0/5 * * * ?" CronTrigger示例2 - 一个表达式,用于建立在分钟后10秒(即上午10:00:10,上午10:05:10等)每5分钟触发一次的触发器。 "10 0/5 * * * ?" CronTrigger示例3 - 一个表达式,用于在每一个星期三和星期五的10:30,11:30,12:30和13:30建立一个触发器。 "0 30 10-13 ? * WED,FRI" CronTrigger示例4 - 一个表达式,用于建立一个触发器,在每月的第5天和第20天的上午8点到上午10点之间每隔半小时触发一次。请注意,触发器不会在上午10点,仅在8点,8点,9点和9点30分 "0 0/30 8-9 5,20 * ?" 请注意,一些调度要求过于复杂,没法用一个触发器来表示 - 例如“上午9点至上午10点之间每5分钟一次,下午1点至10点之间每20分钟一次”。在这种状况下解决方案是简单地建立两个触发器,并注册他们两个运行相同的工做。

CronTrigger实例使用TriggerBuilder(用于触发器的主属性)和WithCronSchedule扩展方法(用于CronTrigger特定的属性)构建。 您也可使用CronScheduleBuilder的静态方法来建立计划。 创建一个触发器,每隔上午8点到下午5点,每隔一分钟一次:

trigger = TriggerBuilder.Create()
    .WithIdentity("trigger3", "group1")
    .WithCronSchedule("0 0/2 8-17 * * ?")
    .ForJob("myJob", "group1")
    .Build();
复制代码

创建一个触发器,天天在上午10:42开始:

// we use CronScheduleBuilder's static helper methods here trigger = TriggerBuilder.Create() .WithIdentity("trigger3", "group1") .WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(10, 42)) .ForJob(myJobKey) .Build(); 复制代码

要么 -

trigger = TriggerBuilder.Create()
    .WithIdentity("trigger3", "group1")
    .WithCronSchedule("0 42 10 * * ?")
    .ForJob("myJob", "group1")
    .Build();
复制代码

创建一个触发器,将在星期三上午10:42,在系统默认的时区之外的其余时间触发:

trigger = TriggerBuilder.Create()
    .WithIdentity("trigger3", "group1")
    .WithSchedule(CronScheduleBuilder
        .WeeklyOnDayAndHourAndMinute(DayOfWeek.Wednesday, 10, 42)
        .InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("Central America Standard Time")))
    .ForJob(myJobKey)
    .Build();
复制代码

要么 -

trigger = TriggerBuilder.Create()
    .WithIdentity("trigger3", "group1")
    .WithCronSchedule("0 42 10 ? * WED", x => x
        .InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("Central America Standard Time")))
    .ForJob(myJobKey)
    .Build();
复制代码

如下指令可用于通知QuartzCronTrigger发生中止做业时应该执行的操做。(本教程的“更多关于触发器”部分介绍了中止做业状况)。这些指令被定义为常量(而且API文档具备对其行为的描述)。说明包括:

  • MisfireInstruction.IgnoreMisfirePolicy
  • MisfireInstruction.CronTrigger.DoNothing
  • MisfireInstruction.CronTrigger.FireOnceNow

全部触发器都有MisfireInstrution.SmartPolicy指令可供使用,而且此指令也是全部触发器类型的默认值。CronTrigger将“智能策略”指令解释为MisfireInstruction.CronTrigger.FireOnceNow。CronTrigger.UpdateAfterMisfire()方法的API文档解释了此行为的确切详细信息。 在构建CronTriggers时,您能够将缺火指令指定为cron时间表的一部分(经过WithCronSchedule扩展方法):

trigger = TriggerBuilder.Create()
    .WithIdentity("trigger3", "group1")
    .WithCronSchedule("0 0/2 8-17 * * ?", x => x
        .WithMisfireHandlingInstructionFireAndProceed())
    .ForJob("myJob", "group1")
    .Build();
复制代码

其余

咱们能够看一下,源码中对IQuartzScheduleJobManagerScheduleAsync方法的封装,其实就是Scheduler.ScheduleJob处理了一下。

image.png

若是要使用模块的PostInitialize方法中解析和使用它来调度做业,也是能够的。

using System.Reflection;
using Abp.Dependency;
using Abp.Modules;
using Abp.Quartz.Configuration;
using Abp.Threading.BackgroundWorkers;
using Quartz;

namespace Abp.Quartz
{
    [DependsOn(typeof (AbpKernelModule))]
    public class AbpQuartzModule : AbpModule
    {
        public override void PreInitialize()
        {
            IocManager.Register<IAbpQuartzConfiguration, AbpQuartzConfiguration>();

            Configuration.Modules.AbpQuartz().Scheduler.JobFactory = new AbpQuartzJobFactory(IocManager);
        }

        public override void Initialize()
        {
            IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
        }

        public override void PostInitialize()
        {
            IocManager.RegisterIfNot<IJobListener, AbpQuartzJobListener>();

            Configuration.Modules.AbpQuartz().Scheduler.ListenerManager.AddJobListener(IocManager.Resolve<IJobListener>());

            if (Configuration.BackgroundJobs.IsJobExecutionEnabled)
            {
                IocManager.Resolve<IBackgroundWorkerManager>().Add(IocManager.Resolve<IQuartzScheduleJobManager>());
            }
        }
    }
}

复制代码

JobBase封装的一些方法,继承自IJob

image.png

ABP+AdminLTE+Bootstrap Table权限管理系统一期 Github:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMS

相关文章
相关标签/搜索