首页 > 其他分享 >Quartz.NET--JOB作业

Quartz.NET--JOB作业

时间:2022-11-09 17:03:24浏览次数:37  
标签:触发器 Quartz -- 作业 JobDataMap scheduler NET 执行 JobDetail


作业流程是在调度器的统一调度下完成的,它可以调度多个作业,触发器提供作业执行的条件(每天 8:00 am),触发器与作业关联,它们是 1:N 的关系,1个触发器可以关联1个或多个作业。


附带的作业

      我们知道要实现自己的作业功能只要继承 IJob 接口并实现 Execute(JobExecutionContext context) 方法,再把它添加到调度器,调度器会调用执行Execute(JobExecutionContext context) 方法。调用期间,调度器会跟踪作业和它们的执行次数。Quartz.NET 默认提供了 FileScanJob 监视某个文件是否被修改,NativeJob 执行指定程序,NoOpJob 空操作用来给系统调用 ITriggerListener 、IJobListener ,以及 SendMailJob 邮件发送作业


Quartz.NET--JOB作业_.net


它有一个存储作业执行时数据的重要属性:MergedJobDataMap,它是 JobDataMap 类型,也可以使用 JobExecutionContext.JobDetail.JobDataMap 来获得 JobDataMap 对象的引用。作为传递参数的容器,JobDataMap 间接继承了 DirtyFlagMap,DirtyFlagMap 内嵌了 Hashtable 容器,它有一组数据读写方法。可以使用 Visual Studio 的类图来查看。

Quartz.NET--JOB作业_数据_02


当实现一个真实的作业类时,一些属性是需要告知Quartz的,也是您希望该作业需要有的。这就需要通过JobDetail类,这个类在前面我们已经简单介绍过。

下面我们看一下作业的本质,以及生命周期。还是看看前面的例子:


Lesson1

// construct a scheduler factory 
ISchedulerFactory schedFact = new StdSchedulerFactory();
// get a scheduler
IScheduler sched = schedFact.GetScheduler();
sched.Start();
// construct job info
JobDetail jobDetail = new JobDetail("myJob", null, typeof(DumbJob));
// fire every hour
Trigger trigger = TriggerUtils.MakeHourlyTrigger();
// start on the next even hour
trigger.StartTime = TriggerUtils.GetEvenHourDate(DateTime.UtcNow);
trigger.Name = "myTrigger";
sched.ScheduleJob(jobDetail, trigger);


public class DumbJob : IJob
{
public DumbJob() { }
publicvoid Execute(JobExecutionContext context)
{
Console.WriteLine("DumbJob is executing.");
}
}

如上例所示,向scheduler提供JobDetail实例,就能指向作业执行。scheduler每次执行(Execute方法)作业前,都新生成一个作业实例。由于是没有参数的构造器,每次作业执行,数据都没清一次。


JobDataMap


   在作业实例执行的时候,JobDataMap可以用来保存任何数量对象(可序列化)的。JobDataMap继承自IDictionary接口,添加一些便捷的方法,以便存储和获得原型数据。



以下是添加到scheduler之前,向JobDataMap存放数据的代码片段:


jobDetail.JobDataMap[
"jobSays"
] =
"Hello World!"
;

jobDetail.JobDataMap[
"myFloatValue"
] = 3.141f;

jobDetail.JobDataMap[
"myStateData"
] =
new
ArrayList();

以下是在作业执行时,取数据的代码片段:


public

class
DumbJob : IJob

{


public

void
Execute(JobExecutionContext context)


{




string
instName = context.JobDetail.Name;




string
instGroup = context.JobDetail.Group;



JobDataMap dataMap = context.JobDetail.JobDataMap;




string
jobSays = dataMap.GetString(
"jobSays"
);





float
myFloatValue = dataMap.GetFloat(
"myFloatValue"
);



ArrayList state = (ArrayList) dataMap[
"myStateData"
];



state.Add(DateTime.UtcNow);



Console.WriteLine(
"Instance {0} of DumbJob says: {1}"
, instName, jobSays);


}

}

 

 如果需要用JobStore来做持久化的话,就需要小心存在JobDataMap的是什么了。因为存放的对象是要被序列化的,那么就很容易出现对象的版本问题。显然,.Net的标准数据类型是安全的,除此之外,序列化的对象实例,任何变化,都会导致版本兼容问题。或者干脆只允许原型数据类型和字符串能保存,这样能避免以后序列化版本冲突问题。


在作业执行时,JobDataMap可以从JobExecutionContext中获得。这时候它是JobDetail和Trigger中的JobDataMap合并,是后来同名对象的覆盖。
下面是在作业执行时,从JobExecutionContext中获得JobDataMap的代码片段:

public class DumbJob : IJob
{
public void Execute(JobExecutionContext context)
{
string instName = context.JobDetail.Name;
string instGroup = context.JobDetail.Group;

// Note the difference from the previous example
JobDataMap dataMap = context.MergedJobDataMap;

string jobSays = dataMap.GetString("jobSays");
float myFloatValue = dataMap.GetFloat("myFloatValue");
ArrayList state = (ArrayList) dataMap.Get("myStateData");
state.Add(DateTime.UtcNow);

Console.WriteLine("Instance {0} of DumbJob says: {1}", instName, jobSays);
}
}

有状态与无状态的作业

   以上我们的作业实例都是从 IJob 继承,Quartz.NET 里还有 IStatefulJob 、IInterruptableJob,它的声明方式为:



public interface IStatefulJob : IJob 
{
}

public interface IInterruptableJob : IJob
{
void Interrupt();
}

      IInterruptableJob 接口提供了一个中断方法,但是 IStatefulJob 没有自己的方法。从 Quartz.NET 官方了解到:

一个 Job 实例可以被定义为“有状态的”或者“无状态的”。在执行无状态的任务过程中任何对 JobDataMap 所作的更改都将丢失。有状态的任务恰好相反,它在任务的每次执行之后重新存储 JobDataMap 。有状态任务的一个缺点就是它不能并发执行。也就是说,如果任务有状态,那么当触发器试图触发它,触发器就会被阻塞直到前面的执行完成。想使任务有状态,它就要实现 IStatefulJob 接口而不是实现IJob接口。


作业实例,可以被指定为“statefull”,或者“non-statefull”。Non-statefull作业只在JobDataMap添加到scheduler时有数据。就是意味着,在下一次作业执行时,任何作业状态数据(JobDataMap)的修改丢将丢失或看不见。正如您猜测的那样,statefull作业正好相反,作业的每次执行,JobDataMap都会重新保存,这给statefull作业的负作用,就是不能并发执行。也就是说,如果一个statefull作业,触发器已经触发正在执行了,下个触发器将会被阻塞,直到前一个执行完成。
  标识一个statefull作业,只要继承IStatefullJob接口,而不是IJob接口。

Job 'Instances'


   这个需要最后明确的是,您可以创建一个作业类,通过创建多个JobDetail实例,存储在scheduler中,每个实例都有自己的属性集及JobDataMap。


 

 当与作业关联的触发器触发时,作业通过JobFactory实例化。缺省的JobFactory调用Activator.CreateInstance。


Other Attributes Of Jobs

这里列一下JobDetail对象的其他属性:

  • Durable - 一个non-durable作业, 当没有与之关联的active trigger时,会自动从scheduler中删除的。
  • Volatile - 一个volatile作业, 在re-starts scheduler之间是不保留的。
  • RequestsRecovery - 一个"requests recovery"作业,在scheduler“hard shutdown”的情况下,或者机器断电的时候,当scheduler重启时,作业重新执行。JobExecutionContext.isRecovering()返回true。
  • JobListeners - 作业可以没有或多个JobListeners。作业执行时,listeners会被提醒。更多讨论后面专门讨论。

The Job.Execute(..) Method






为什么作业和触发分开

很多作业调度程序,作业和触发没有明显的分开界限。有些作业定义为一个作业识别号和相应的执行时间。还有些更像Quartz.NET作业和触发的聚合。当开发Quartz的时候,Quartz team决定,把调度和所要执行的动作分开(trigger)。据我们所知,这将带来很多便捷。例如:

  • 作业可以独立trigger存储在scheduler中,多个trigger关联同一个作业。
  • 松耦合可以重新调度已经过期作业,而不需要重新定义。也可以修改替换触发器而不需要重新定义与之相关的作业。

识别符Identifiers

与scheduler注册作业和触发器时,需要指定识别名称的。作业、触发器也能够安祖存放,为日后维护时组织分类作业和触发器提供方便。作业和触发器的名称在组内必须是唯一的。也就是说,正确的识别符是名称 + 组,如果让组名(Job or Trigger)留空 'null', 就等于说属于SchedulerConstants.DefaultGroup。



标签:触发器,Quartz,--,作业,JobDataMap,scheduler,NET,执行,JobDetail
From: https://blog.51cto.com/u_15870687/5837354

相关文章

  • 公司要求员工签署奋斗者协议
    【公司要求员工自愿签奋斗者协议】9月2日,据网友“伤寒杂病论”爆料,成渝钒钛科技有限公司让员工自愿签署《奋斗者自愿申请书》,做“公司奋斗者”,需自愿加班,放弃带薪休假,放弃加......
  • 关于前端:如何实现并发请求数量控制?
    原文地址: https://juejin.cn/post/7163522138698153997//并发请求函数constconcurrencyRequest=(urls,maxNum)=>{returnnewPromise((resolve)=>{......
  • 设计模式利剑14-迭代器模式
    定     义:它提供一种方法访问一个容器对象中各个元素,而又不需暴露该对对象的内部细节,,Iterator模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以......
  • springboot+vue前后端分离国际化
    一,概要前端使用vue-i18n框架来实现国际化功能,国际化数据存储在数据库里,由后端接口提供,使用pinia缓存。后端使用redis缓存,并使用拦截器对响应中的提示信息做国际化。二......
  • 通勤人员可出京,该紧的时候就要紧
    “ 疫情横行,该紧的时候就是要紧。”最新疫情播报随着数量的降低,排查的升级,人员的流动已经有了更多的自由。过滤器所谓过滤器顾名思义是用来过滤的,Java的过滤器能够为我们提......
  • Spring Boot 引起的 “堆外内存泄漏”,太坑了,快看看你什么版本!
    作者:纪兵,2015年加入美团,目前主要从事酒店C端相关的工作。原文:https://tech.meituan.com/2019/01/03/spring-boot-native-memory-leak.html背景为了更好地实现对项目的管......
  • 设计模式利剑17-门面模式
    定     义:要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行,门面模式提供一个高层次的接口,使得子系统更易于使用优     点:           ......
  • 前端路由
    1.路由基本概念和原理(1)路由本质:对应关系后端路由:根据不同用户URL请求,返回不同内容        本质:URL请求地址与服务器资源之间的对应关系前端路由:根......
  • 创新,智造,服务:流辰信息以匠人之心勇往直前!
    在软件服务行业,流辰信息奋斗至今已有六个年头,在六年奋勇拼搏的历程中,流辰始终不忘初心,坚守品质、创新、服务的经营理念,在低代码开发平台服务市场深耕细作,坚持研发创新,为产......
  • 367页资料详解企业数字化转型,覆盖多行业!附下载
    ​据工信部网站11月8日消息,为助力中小企业数字化转型,工业和信息化部组织相关单位共同研究制定了《中小企业数字化水平评测指标(2022年版)》(以下简称《评测指标》)。《指南》明......