任务调度之Quartz.Net基础
最近公司要求将之前的系统设计文档补上,于是大家就都被分配了不同的任务,紧锣密鼓的写起了文档来。发现之前项目中使用了Quartz.Net来做一些定时任务的调度,比如定时的删除未支付的订单,定时检查支付状态是否回调成功等业务。现在看起来对代码居然有点陌生了,于是决定写篇博文来记录下Quartz.Net 的基本使用。
这里以Quartz.Net 3.0+为例,Quartz.Net中最核心三大对象分别为:
- IScheduler: 单元/实例,通过这里完成定时任务的配置,只有单元启动后里面的作业才能正常运行
- IJob:定时执行的作业就是Job
- ITrigger:定时策略
我们先来看一下最简单的使用吧,以下代码创建一个Scheduler并启动之。
StdSchedulerFactory factory = new StdSchedulerFactory();
IScheduler scheduler = await factory.GetScheduler();
await scheduler.Start();
然后我们创建一个继承自IJob的TestJob类,其主要实现IJob的Execute方法,该方法则为当该任务被调度执行的时候所执行的方法。
public class TestJob : IJob
{
public TestJob()
{
Console.WriteLine("This is TestJob的构造函数。。。");
} public async Task Execute(IJobExecutionContext context)
{
await Task.Run(() =>
{
Console.WriteLine($"This is {Thread.CurrentThread.ManagedThreadId} {DateTime.Now}");
});
}
}
接下来使用JobBuilder创建我们的TestJob
IJobDetail jobDetail = JobBuilder.Create<TestJob>()
.WithIdentity("testjob", "group")
.WithDescription("This is TestJob")
.Build();
创建完Job后需要添加一个trigger,其中StartAt可以指定在隔多少时间后开始触发作业,StartNow则是马上开始,WithCronSchedule是使用Cron表达式来标识时间,关于Cron表达式可以参考另一篇博文
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("testtrigger1", "group")
.StartAt(new DateTimeOffset(DateTime.Now.AddSeconds()))
//.StartNow()//StartAt
.WithCronSchedule("0/10 * * * * ?")//每隔10秒钟
.WithDescription("This is testjob's Trigger")
.Build();
创建完Job和trigger后,最后需要将其添加到Scheduler中
await scheduler.ScheduleJob(jobDetail, trigger);
这样最简单的作业调度就完成了。但是在实际工作中,有时候我们需要传递参数到Job中,这该怎么做呢?Quartz.Net为我们提供了两种方法:
- 通过在创建Job的时候在其JobDataMap中添加参数,然后在Job的Execute方法中通过context.JobDetail.JobDataMap来获取
jobDetail.JobDataMap.Add("param", "value1");
JobDataMap dataMap = context.JobDetail.JobDataMap;
dataMap.Get("param")
2. 通过在trigger中通过trigger.JobDataMap.Add添加参数,在Job中通过context.Trigger.JobDataMap获取
trigger.JobDataMap.Add("param", "value2");
JobDataMap dataMap = context.Trigger.JobDataMap;
dataMap.Get("param")
3. 在Job中获取参数还可以通过context.MergedJobDataMap来获取参数,但是如果同时通过JobDetail和trigger传递同一个参数,则只能获取到最后添加的那个参数,前面添加的参数会被丢弃,例如上面都添加了param参数,则下面代码获取到的值为value2
JobDataMap dataMap = context.MergedJobDataMap;
Console.WriteLine(dataMap.Get("param"));
到这里,我们知道了通过Cron表达式的Trigger,虽然Cron可以很灵活的定制时间规则,但是Quartz.Net也提供了另一个常用的Trigger,那就是SimpleTrigger,它的使用方法如下,其表示每隔10秒钟执行一次,最多执行10次
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds()
.WithRepeatCount()
//.RepeatForever())
.WithDescription("This is testjob's Trigger")
.Build();
我们知道,在Quartz.Net 3.0之前的版本有一个IStatefulJob接口,表示有状态的作业,意思是上一次的执行结果可以影响到下一次,而在3.0之后的版本,通过特性 PersistJobDataAfterExecution 来实现,下面代码中的DisallowConcurrentExecution 特性表示拒绝同一时间重复执行,即同一任务只能是串行的执行,避免的并发带来的问题。
[PersistJobDataAfterExecution]//执行后保留数据,更新JobDataMap
[DisallowConcurrentExecution]//拒绝同一时间重复执行,同一任务串行
public class TestStatefulJob : IJob
{ }
Quartz.Net 提供了三个Listerner,即ISchedulerListener,IJobListener,ITriggerListener来分别各个环节的事件,我们可以分别来定义它们的三个实现类
public class CustomSchedulerListener : ISchedulerListener
{
public async Task JobAdded(IJobDetail jobDetail, CancellationToken cancellationToken = default(CancellationToken))
{
await Task.Run(() =>
{
Console.WriteLine($"This is {nameof(CustomSchedulerListener)} JobAdded {jobDetail.Description}");
});
} public Task JobDeleted(JobKey jobKey, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public Task JobInterrupted(JobKey jobKey, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public Task JobPaused(JobKey jobKey, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public Task JobResumed(JobKey jobKey, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public Task JobScheduled(ITrigger trigger, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public Task JobsPaused(string jobGroup, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public Task JobsResumed(string jobGroup, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public Task JobUnscheduled(TriggerKey triggerKey, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public Task SchedulerError(string msg, SchedulerException cause, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public Task SchedulerInStandbyMode(CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public Task SchedulerShutdown(CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public Task SchedulerShuttingdown(CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public async Task SchedulerStarted(CancellationToken cancellationToken = default(CancellationToken))
{
await Task.Run(() =>
{
Console.WriteLine($"This is {nameof(CustomSchedulerListener)} SchedulerStarted ");
});
} public async Task SchedulerStarting(CancellationToken cancellationToken = default(CancellationToken))
{
await Task.Run(() =>
{
Console.WriteLine($"This is {nameof(CustomSchedulerListener)} SchedulerStarting ");
});
} public Task SchedulingDataCleared(CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public Task TriggerFinalized(ITrigger trigger, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public Task TriggerPaused(TriggerKey triggerKey, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public Task TriggerResumed(TriggerKey triggerKey, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public Task TriggersPaused(string triggerGroup, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
} public Task TriggersResumed(string triggerGroup, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
}
}
public class CustomJobListener : IJobListener
{
public string Name => "CustomJobListener"; public async Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken))
{
await Task.Run(()=> {
Console.WriteLine($"CustomJobListener JobExecutionVetoed {context.JobDetail.Description}");
});
} public async Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken))
{
await Task.Run(() => {
Console.WriteLine($"CustomJobListener JobToBeExecuted {context.JobDetail.Description}");
});
} public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default(CancellationToken))
{
await Task.Run(() => {
Console.WriteLine($"CustomJobListener JobWasExecuted {context.JobDetail.Description}");
});
}
}
public class CustomTriggerListener : ITriggerListener
{
public string Name => "CustomTriggerListener"; public async Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default(CancellationToken))
{
await Task.Run(() =>
{
Console.WriteLine($"CustomTriggerListener TriggerComplete {trigger.Description}");
});
} public async Task TriggerFired(ITrigger trigger, IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken))
{
await Task.Run(() =>
{
Console.WriteLine($"CustomTriggerListener TriggerFired {trigger.Description}");
});
} public async Task TriggerMisfired(ITrigger trigger, CancellationToken cancellationToken = default(CancellationToken))
{
await Task.Run(() =>
{
Console.WriteLine($"CustomTriggerListener TriggerMisfired {trigger.Description}");
});
} /// <summary>
/// 要不要放弃job
/// </summary>
/// <param name="trigger"></param>
/// <param name="context"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<bool> VetoJobExecution(ITrigger trigger, IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken))
{
await Task.Run(() =>
{
Console.WriteLine($"CustomTriggerListener TriggerMisfired {trigger.Description}");
});
return false;//false才能继续执行
}
}
之后我们需要在创建Scheduler的时候将其添加到scheduler中
StdSchedulerFactory factory = new StdSchedulerFactory();
IScheduler scheduler = await factory.GetScheduler();
scheduler.ListenerManager.AddSchedulerListener(new CustomSchedulerListener());
scheduler.ListenerManager.AddTriggerListener(new CustomTriggerListener());
scheduler.ListenerManager.AddJobListener(new CustomJobListener());
await scheduler.Start();
至此,我们的demo中都是使用console来自定义的记录操作过程,但是Quartz.Net也提供了一个日志组件 ILogProvider,我们创建一个CustomConsoleLogProvider,其实现了ILogProvider
public class CustomConsoleLogProvider : ILogProvider
{
public Logger GetLogger(string name)
{
return (level, func, exception, parameters) =>
{
if (level >= LogLevel.Info && func != null)
{
Console.WriteLine($"[{ DateTime.Now.ToLongTimeString()}] [{ level}] { func()} {string.Join(";", parameters.Select(p => p == null ? " " : p.ToString()))} 自定义日志{name}");
}
return true;
};
}
public IDisposable OpenNestedContext(string message)
{
throw new NotImplementedException();
} public IDisposable OpenMappedContext(string key, string value)
{
throw new NotImplementedException();
}
}
然后通过Quartz.Logging.LogProvider来添加自定义的LogProvider,其在运行中会通过GetLogger来记录日志。
LogProvider.SetCurrentLogProvider(new CustomConsoleLogProvider());
到这里关于Quartz.Net的基本使用就介绍到这里,其进阶待下一篇再继续。
任务调度之Quartz.Net基础的更多相关文章
- 免费开源的DotNet任务调度组件Quartz.NET(.NET组件介绍之五)
很多的软件项目中都会使用到定时任务.定时轮询数据库同步,定时邮件通知等功能..NET Framework具有“内置”定时器功能,通过System.Timers.Timer类.在使用Timer类需要面对 ...
- 任务调度框架Quartz原理简介
[TOC] 第一章 Quartz 1.1 Quartz概念 Quartz是OpenSymphony开源组织的一个Java开源项目, 在2009被Terracotta收购.Quartz官网 1.2 Qu ...
- Java任务调度框架Quartz入门
Quartz[kwɔːts]:石英,其框架和名字一样简单朴素又不失魅力,在Java程序界,Quartz大名鼎鼎,很多Java应用几乎都集成或构建了一个定时任务调度系统,Quartz是一个定时任务调度框 ...
- [源码分析] 定时任务调度框架 Quartz 之 故障切换
[源码分析] 定时任务调度框架 Quartz 之 故障切换 目录 [源码分析] 定时任务调度框架 Quartz 之 故障切换 0x00 摘要 0x01 基础概念 1.1 分布式 1.1.1 功能方面 ...
- 任务调度TimerTask&Quartz的 Java 实现方法与比较
文章引自--https://www.ibm.com/developerworks/cn/java/j-lo-taskschedule/ 前言 任务调度是指基于给定时间点,给定时间间隔或者给定执行次数自 ...
- 企业级任务调度框架Quartz(1) --企业应用中的任务调度介绍
由于目前的工作内容为建行CLPM批处理业务的设计工作,所以很好的理解批处理所用的任务调度框架Quartz势在必行:为了能够更好的去服务于工作,也 为了提升自己,所以我学习了Quartz Job Sch ...
- 通过源码分析Java开源任务调度框架Quartz的主要流程
通过源码分析Java开源任务调度框架Quartz的主要流程 从使用效果.调用链路跟踪.E-R图.循环调度逻辑几个方面分析Quartz. github项目地址: https://github.com/t ...
- SpringBoot整合任务调度框架Quartz及持久化配置
目录 本篇要点 SpringBoot与Quartz单机版快速整合 引入依赖 创建Job 调度器Scheduler绑定 自动配置,这里演示SimpleScheduleBuilder 手动配置,这里演示C ...
- Spring任务调度之Quartz集成
推荐一个博客:http://blog.csdn.net/column/details/14251.html 基本概念 Job:是一个接口,只有一个方法void execute(JobExecution ...
随机推荐
- (大型网站之Nginx)图解正向代理、反向代理、透明代理
一.正向代理(Forward Proxy) 一般情况下,如果没有特别说明,代理技术默认说的是正向代理技术.关于正向代理的概念如下: 正向代理(forward)是一个位于客户端[用户A]和原始服务器(o ...
- Prometheus初体验(三)
一.安装部署 Prometheus基于Golang编写,编译后的软件包,不依赖于任何的第三方依赖.用户只需要下载对应平台的二进制包,解压并且添加基本的配置即可正常启动Prometheus Server ...
- RabbitMQ入门学习系列(四) 发布订阅模式
发布订阅模式 什么时发布订阅模式 把消息发送给多个订阅者.也就是有多个消费端都完整的接收生产者的消息 换句话说 把消息广播给多个消费者 消息模型的核心 RabbitMQ不发送消息给队列,生产者也不知道 ...
- 2018-2019-2 20165212《网络对抗技术》Exp9 Web安全基础
2018-2019-2 20165212<网络对抗技术>Exp9 Web安全基础 基础问题回答 1.SQL注入攻击原理,如何防御? 原理:SQL注入,就是通过把SQL命令插入到Web表单递 ...
- Tomcat启动过程中找不到JAVA_HOME JRE_HOME的解决方法
转自:http://blog.sina.com.cn/s/blog_61c006ea0100l1u6.html 原文: 在XP上明明已经安装了JDK1.5并设置好了JAVA_HOME,可偏偏Tomca ...
- 随机森林算法OOB_SCORE最佳特征选择
RandomForest算法(有监督学习),可以根据输入数据,选择最佳特征组合,减少特征冗余:原理:由于随机决策树生成过程采用的Boostrap,所以在一棵树的生成过程并不会使用所有的样本,未使用的样 ...
- 利用JS-SDK微信分享接口调用(后端.NET)
一直都想研究一下JS-SDK微信分享的接口调用,由于最近工作需要,研究了一下,目前只是实现了部分接口的调用:其他接口调用也是类似的: 在开发之前,需要提前准备一个微信公众号,并且域名JSAPI 配置接 ...
- JS实现文字向上无缝滚动轮播
效果图: 全部代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...
- postgresQL 服务器端守护进程
- Mybatis自定义控制台打印sql的日志工具
调试mybatis源码时,想要更改日志的的实现工具,首先需要了解其原理. 源码包里有这部分的解释,翻译如下: Mybatis 的内置日志工厂提供日志功能,内置日志工厂将日志交给以下其中一种工具作代理: ...