QuartzNet的基本使用,Scheduler,Job,Trigger的应用

Quartz.Net的基本使用方法

Quartz.Net的基本使用是比较简单的,主要是对下面三个工具的创建和使用。

  1. Scheduler调度器
  2. Job执行的动作
  3. Trigger触发器

Scheduler的创建和使用

scheduler的创建有几种不同的方式,但一般可以直接使用其提供的工厂类直接创建

  • 通过工厂类创建-----像StdSchedulerFactory和DirectSchedulerFactory
   /*StdFactory是用到最多的情况,亦可以通过NameValueCollection读取不同形式的键值对参数(.prop,.txt应该都可以),其创建的Scheduler即为StdScheduler类型*/
   StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();

   IScheduler scheduler = await stdSchedulerFactory.GetScheduler();

   /*directfatory和stdfactory有很多区别,一般可以用于更细节的Custom,
     1. directfactory为单例设计
     2. directfactory可以通过CreateScheduler(args)自定scheduler 
     3. directfactory无法通过键值对获取初始属性 */
   DirectSchedulerFactory directSchedulerFactory = DirectSchedulerFactory.Instance;


   directSchedulerFactory.CreateScheduler(new DefaultThreadPool(), new RAMJobStore());

   IScheduler scheduler2 = await directSchedulerFactory.GetScheduler();

  • 绑定Job和Trigger
    在scheduler里绑定对应的Job和Trigger,然后调用Start()开始即可。
     static async Task Main(string[] args)
    {
    
    
        StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();

        IScheduler scheduler = await stdSchedulerFactory.GetScheduler();
        //这里先直接使用builder创建trigger,在后面再详细的解释(PS:withRepeateCount的实际执行次数为count+1)
        ITrigger trigger = TriggerBuilder.Create().WithSimpleSchedule(action => {
    
     action.WithIntervalInSeconds(2).WithRepeatCount(1); }).WithIdentity("TriggerOne").Build();

        //创建一个简单的Job,一般的Job都有很多的参数,这里先用无参的方法替代一下。
        IJobDetail job = JobBuilder.Create<SimpleJob>().WithIdentity("JOB:one").Build();

        await scheduler.ScheduleJob(job, trigger);

        await scheduler.Start();

        //停主线程--查看效果
        Thread.Sleep(7000);
        
    }

    public class SimpleJob : IJob

    {
    
    
        public async Task Execute(IJobExecutionContext context)
        {
    
    
            Console.WriteLine("Hello QuartZnet!");
        }
    }

在这里插入图片描述

Job的创建和参数的传递

只要实现IJob接口的类就可以称之为Job类,
IJob接口只有Execute(IJobExecutionContext context)方法
其context为上下文参数,保存着IJob执行过程的信息,
也保存着需要的参数。
方法体则为具体的定时业务

Job的传参方式

Job的传参方式为通过JobDetail的JobDataMap进行键值对存取。


static async Task Main(string[] args)
{
    
    
    StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();

    IScheduler scheduler = await stdSchedulerFactory.GetScheduler();

    ITrigger trigger = TriggerBuilder.Create().WithSimpleSchedule(action => {
    
     action.WithIntervalInSeconds(2).WithRepeatCount(1); }).WithIdentity("TriggerOne").Build();

    IJobDetail job = JobBuilder.Create<SimpleJob>().WithIdentity("JOB:one").Build();

    //在键值对中添加参数
    job.JobDataMap.Add("UserName", "小明");
    job.JobDataMap.Add("Pets", new List<string>() {
    
     "小狗","小猫","乌龟","仓鼠" });

    await scheduler.ScheduleJob(job, trigger);
    await scheduler.Start();

    Thread.Sleep(7000);
    
}


public class SimpleJob : IJob
{
    
    
    public async Task Execute(IJobExecutionContext context)
    {
    
    
        Console.WriteLine("Hello QuartZnet!");
        //再context上下文中获取参数[也可以获取执行的其他信息]
        string argOne = (string)context.JobDetail.JobDataMap.Get("UserName");
        List<string> argTwo = (List<string>)context.JobDetail.JobDataMap.Get("Pets");

        Console.WriteLine(argOne);
        argTwo.ForEach(item => {
    
     Console.WriteLine(item); });

    }
}

PS: 不要在Job类中添加自定义的构造函数,因为JobBuilder是无法使用DI(依赖注入)配置Job的,故无法使用构造函数传参

Job的ID设置

当你需要创建不确定量的任务时,你需要设置Job的ID不唯一。即:
不能多个scheduler启动一个相同ID的Job.

错误例:

StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
//假设有两个调度器,
IScheduler scheduler = await stdSchedulerFactory.GetScheduler();

IScheduler scheduler2 = await stdSchedulerFactory.GetScheduler();

ITrigger trigger = TriggerBuilder.Create().WithSimpleSchedule(action => {
    
     action.WithIntervalInSeconds(2).WithRepeatCount(1); }).WithIdentity("TriggerOne").Build();

IJobDetail job = JobBuilder.Create<SimpleJob>().WithIdentity("ThisOne").Build();


job.JobDataMap.Add("UserName", "小明");
job.JobDataMap.Add("Pets", new List<string>() {
    
     "小狗","小猫","乌龟","仓鼠" });

await scheduler.ScheduleJob(job, trigger);
;
await scheduler.Start();

//ObjectAlreadyExistsException,
//Unable to store Job: 'DEFAULT.ThisOne', because one already exists with this identification.'
//这里的异常即为JobID已经存在(或者说是重复)
await scheduler2.ScheduleJob(job, trigger);

await scheduler2.Start();

Thread.Sleep(7000);

在这里插入图片描述

ID重复的解决方法
  1. 设置不同的ID(trigger也需要设置)

//本测试在Main方法中,故直接创建不同的Job/Trigger对象使用不同的ID即可
//如果你提供方法/API来创建任务,推荐使用:
//UUID,数据库生成ID
//来保证不重复
IScheduler scheduler = await stdSchedulerFactory.GetScheduler();

IScheduler scheduler2 = await stdSchedulerFactory.GetScheduler();

ITrigger trigger = TriggerBuilder.Create().WithSimpleSchedule(action => {
    
     action.WithIntervalInSeconds(2).WithRepeatCount(1); }).WithIdentity("TriggerOne").Build();

ITrigger trigger2 = TriggerBuilder.Create().WithSimpleSchedule(action => {
    
     action.WithIntervalInSeconds(2).WithRepeatCount(1); }).WithIdentity("TriggerTwo").Build();


IJobDetail job = JobBuilder.Create<SimpleJob>().WithIdentity("ThisOne").Build();

IJobDetail job2 = JobBuilder.Create<SimpleJob>().WithIdentity("ThisTwo").Build();


job.JobDataMap.Add("UserName", "小明");
job.JobDataMap.Add("Pets", new List<string>() {
    
     "小狗","小猫","乌龟","仓鼠" });

job2.JobDataMap.Add("UserName", "小明");
job2.JobDataMap.Add("Pets", new List<string>() {
    
     "小狗", "小猫", "乌龟", "仓鼠" });

await scheduler.ScheduleJob(job, trigger);

await scheduler.Start();

await scheduler2.ScheduleJob(job2, trigger2);

await scheduler2.Start();

Thread.Sleep(7000);
  1. UnScheduleJob(trigger);解绑Trigger和Job

通过UnScheduleJob可以解绑trigger和Job
可以在任何时候解绑
但也有着不同的效果

  • Start后立马解绑------Job不会被执行
StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();

//假设有两个调度器,
IScheduler scheduler = await stdSchedulerFactory.GetScheduler();

ITrigger trigger = TriggerBuilder.Create().WithSimpleSchedule(action => {
    
     action.WithIntervalInSeconds(2).WithRepeatCount(1); }).WithIdentity("TriggerOne").Build();


IJobDetail job = JobBuilder.Create<SimpleJob>().WithIdentity("ThisOne").Build();

job.JobDataMap.Add("UserName", "小明");
job.JobDataMap.Add("Pets", new List<string>() {
    
     "小狗","小猫","乌龟","仓鼠" });


await scheduler.ScheduleJob(job, trigger);

await scheduler.Start();

await scheduler.UnscheduleJob(new TriggerKey("TriggerOne"));

Thread.Sleep(6000);

执行效果:
在这里插入图片描述

  • schedule执行完毕后解绑-------同一Job和Trigger可以在解绑后再绑定其他schedule

      StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
    
      //假设有两个调度器,
      IScheduler scheduler = await stdSchedulerFactory.GetScheduler();
    
      IScheduler scheduler2 = await stdSchedulerFactory.GetScheduler();
    
      ITrigger trigger = TriggerBuilder.Create().WithSimpleSchedule(action => {
          
           action.WithIntervalInSeconds(2).WithRepeatCount(1); }).WithIdentity("TriggerOne").Build();
    
      
      IJobDetail job = JobBuilder.Create<SimpleJob>().WithIdentity("ThisOne").Build();
    
      
      job.JobDataMap.Add("UserName", "小明");
      job.JobDataMap.Add("Pets", new List<string>() {
          
           "小狗","小猫","乌龟","仓鼠" });
    
      
      await scheduler.ScheduleJob(job, trigger);
    
      await scheduler.Start();
    
      Thread.Sleep(6000);
      //等待执行完成后解绑job和trigger
      bool isCompleted = scheduler.GetTriggerState(new TriggerKey("TriggerOne")).IsCompleted;
      if(isCompleted)
          await scheduler.UnscheduleJob(new TriggerKey("TriggerOne"));
    
      //再绑定新的scheduler,则可以正常运行了
      await scheduler2.ScheduleJob(job, trigger);
    
      await scheduler2.Start();
    
      Thread.Sleep(7000);
    
对比
  1. 创建新ID的Job和Trigger
    Job/Trigger间彼此独立,可以在同一时间创造多个任务,但是可能线程开销会比较大
  2. 解绑Job和Trigger于scheduler,重复使用Job和Trigger
    同一个Job可重复使用,可能可以节省开销,
    但是如果解绑的时间可能和任务的执行时间造成冲突,导致任务无法执行

Trigger的创建和使用

Trigger为Job的触发器,通过TriggerBuilder进行创建

在QuartZ中,提供了4类现成的生成Trigger类型的方法

  1. WithSimpleSchedule
  2. WithDailyTimeIntervalSchedule
  3. WithCalendarIntervalSchedule
  4. WithCronSchedule

每一种方法都对应一些方面的安排

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

安排Trigger执行的开始/结束时间

可以通过StartAt和StartNow来控制开始时间
反之EndAt可以控制结束的时间。

static async Task Main(string[] args)
{
    
    
    StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();

    //假设有两个调度器,
    IScheduler scheduler = await stdSchedulerFactory.GetScheduler();

    //简单触发器
    ITrigger simpleTrigger = TriggerBuilder.Create().WithSimpleSchedule(option => {
    
    
        option.WithIntervalInSeconds(1);    //可以设置间隔时间
        option.WithRepeatCount(999);        //也可以设置重复次数
    })
        .StartAt(DateTime.Now.AddSeconds(5))          //可以设置哎固定的区间内
        .EndAt(DateTime.Now.AddSeconds(15)).Build();

    IJobDetail jobDetail = JobBuilder.Create<SimpleJob>().WithIdentity("JobOne").Build();

    await scheduler.ScheduleJob(jobDetail,simpleTrigger);

    await scheduler.Start();

    Thread.Sleep(15000);

}

public class SimpleJob : IJob
{
    
    

    public async Task Execute(IJobExecutionContext context)
    {
    
    
        Console.WriteLine(DateTime.Now);
    }
}

请添加图片描述

使用Cron表达式安排任务

CronTrigger的使用更加简单,只需要cron表达式作为参数即可,如果需要了解可以看下图

请添加图片描述

请添加图片描述

也有很多在线工具提供Cron表达式的生成

https://freeformatter.com/cron-expression-generator-quartz.html

例:

static async Task Main(string[] args)
{
    
    
    StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();

    IScheduler scheduler = await stdSchedulerFactory.GetScheduler();

    //Cron表达式无法直接控制重复次数,但可以通过EndAt方法间接调节
    ITrigger Crontrigger = TriggerBuilder.Create().WithCronSchedule("0/2 * * * * ?").StartAt(DateTime.Now.AddSeconds(5)).Build();

    IJobDetail jobDetail = JobBuilder.Create<SimpleJob>().WithIdentity("JobOne").Build();

    await scheduler.ScheduleJob(jobDetail, Crontrigger);

    await scheduler.Start();

    Thread.Sleep(15000);

}

public class SimpleJob : IJob
{
    
    

    public async Task Execute(IJobExecutionContext context)
    {
    
    
        Console.WriteLine(DateTime.Now);
    }
}

猜你喜欢

转载自blog.csdn.net/jamenu/article/details/128626677