Quartz.NET笔记(三) More About Jobs & JobDetails

如你所见,Job相当容易实现。这里只是介绍有关Jobs本质, IJob接口的Execute(..)方法以及JobDetails中需要理解的内容。

在所实现的类成为真正的“Job”时,期望任务所具有的各种属性需要通知给Quartz。通过JobDetail类可以完成这个工作,这个类在前面的章节中曾简短提及过。现在,我们花一些时间来讨论Quartz中Jobs的本质和Job实例的生命周期。首先让我们回顾一下第一课中所看到的代码片断:

Using Quartz.NET

 1 // define the job and tie it to our HelloJob class
 2 IJobDetail job = JobBuilder.Create<HelloJob>()
 3     .WithIdentity("myJob", "group1")
 4     .Build();
 5
 6 // Trigger the job to run now, and then every 40 seconds
 7 ITrigger trigger = TriggerBuilder.Create()
 8   .WithIdentity("myTrigger", "group1")
 9   .StartNow()
10   .WithSimpleSchedule(x => x
11       .WithIntervalInSeconds(40)
12       .RepeatForever())
13   .Build();
14
15 sched.ScheduleJob(job, trigger);

现在考虑如下定义的 HelloJob类:

1 public class HelloJob : IJob
2 {
3     public void Execute(IJobExecutionContext context)
4     {
5         Console.WriteLine("HelloJob is executing.");
6     }
7 }

注意,我们给scheduler传入了一个JobDetail实例,而且这个JobDetail实例只是简单提供了类名来引用被执行的Job。每次scheduler执行这个任务时,它就创建这个类的新实例,然后调用该实例的Execute(..)方法。对这种行为的一个推论就是Job类必须有一个无参数的构造函数。另外一个推论就是它使得Job类中定义的成员数据失去意义,因为这些成员数据值在每次执行的时候被“清空”了。

你可能要问,如何才能为每个Job实例提供属性和配置呢?而且,在执行中如何跟踪Job的状态呢?这些问题的答案是相同的:关键就是JobDataMap,这是JobDetail对象的一部分。

JobDataMap

JobDataMap被用来保存一系列的(序列化的)对象,这些对象在Job执行时可以得到。JobDataMap是IDictionary接口的一个实现,而且还增加了一些存储和读取主类型数据的便捷方法。

下面是将Job加入到scheduler前使用的一些向JobDataMap加入数据的方法。

Setting Values in a JobDataMap:

1 // define the job and tie it to our DumbJob class
2 IJobDetail job = JobBuilder.Create<DumbJob>()
3     .WithIdentity("myJob", "group1") // name "myJob", group "group1"
4     .UsingJobData("jobSays", "Hello World!")
5     .UsingJobData("myFloatValue", 3.141f)
6     .Build();

下面的代码展示了在Job执行过程中从JobDataMap 获取数据的代码:

Getting Values from a JobDataMap:

 1 public class DumbJob : IJob
 2 {
 3     public void Execute(JobExecutionContext context)
 4     {
 5       JobKey key = context.JobDetail.Key;
 6
 7       JobDataMap dataMap = context.JobDetail.JobDataMap;//注意同下面例子的差别
 8
 9       string jobSays = dataMap.GetString("jobSays");
10       float myFloatValue = dataMap.GetFloat("myFloatValue");
11
12       Console.Error.WriteLine("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
13     }
14 } 

如果使用一个持久的JobStore(在本指南的JobStore章节中讨论),那么必须注意存放在JobDataMap中的内容。因为放入JobDataMap中的内容将被序列化,而且容易出现类型转换问题。很明显,标准.NET类型将是非常安全的,但除此之外的类型,任何时候,只要有人改变了你要序列化其实例的类的定义,就要注意是否打破了程序的兼容性。另外,你可以对JobStore和JobDataMap采用一种使用模式:就是只把主类型和String类型存放在Map中,这样就可以减少后面序列化的问题。

有状态和无状态任务

Triggers也可以有JobDataMaps与之相关联。当scheduler中的Job被多个有规律或者重复触发的Triggers所使用时非常有用。对于每次独立的触发,你可为Job提供不同的输入数据。

从Job执行时的JobExecutionContext中取得JobDataMap是惯用手段,它融合了从JobDetail和从Trigger中获的JobDataMap,当有相同名字的键时,它用后者的值覆盖前者值。

Here‘s a quick example of getting data from the JobExecutionContext‘s merged JobDataMap during the job‘s execution:

 1 public class DumbJob : IJob
 2 {
 3     public void Execute(IJobExecutionContext context)
 4     {
 5         JobKey key = context.JobDetail.Key;
 6
 7         JobDataMap dataMap = context.MergedJobDataMap;  // Note the difference from the previous example
 8
 9         string jobSays = dataMap.GetString("jobSays");
10         float myFloatValue = dataMap.GetFloat("myFloatValue");
11         IList<DateTimeOffset> state = (IList<DateTimeOffset>) dataMap["myStateData"];//这个上面的例子中并没有设置,会报错。集合形式的如何设置值呢?待研究!
12         state.Add(DateTimeOffset.UtcNow);
13
14         Console.Error.WriteLine("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
15     }
16 }

Or if you wish to rely on the JobFactory "injecting" the data map values onto your class, it might look like this instead:

 1 public class DumbJob : IJob
 2 {
 3     public string JobSays { private get; set; }
 4     public float FloatValue { private get; set; }
 5
 6     public void Execute(IJobExecutionContext context)
 7     {
 8         JobKey key = context.JobDetail.Key;
 9
10         JobDataMap dataMap = context.MergedJobDataMap;  // Note the difference from the previous example
11
12         IList<DateTimeOffset> state = (IList<DateTimeOffset>) dataMap["myStateData"];//这个上面的例子中并没有设置,会报错。集合形式的如何设置值呢?待研究!
13  state.Add(DateTimeOffset.UtcNow); 14 15 Console.Error.WriteLine("Instance " + key + " of DumbJob says: " + JobSays + ", and val is: " + FloatValue); 16  } 17 }

You‘ll notice that the overall code of the class is longer, but the code in the Execute() method is cleaner. One could also argue that although the code is longer, that it actually took less coding, if the programmer‘s IDE was used to auto-generate the properties, rather than having to hand-code the individual calls to retrieve the values from the JobDataMap. The choice is yours.

Job "Instances"

Many users spend time being confused about what exactly constitutes a "job instance". We‘ll try to clear that up here and in the section below about job state and concurrency.

很多用户在准确地构建 Job实例时花时间并变得困惑,我们试图在本节和下面的章节解释清楚job的状态和并发性。

You can create a single job class, and store many ‘instance definitions‘ of it within the scheduler by creating multiple instances of JobDetails - each with its own set of properties and JobDataMap - and adding them all to the scheduler.

您可以创建单个作业类,和存储许多 ‘实例定义‘ 的计划程序内创建多个实例的 JobDetails-各有其自己的属性和JobDataMap 集-和添加调度程序。

For example, you can create a class that implements the IJob interface called "SalesReportJob". The job might be coded to expect parameters sent to it (via the JobDataMap) to specify the name of the sales person that the sales report should be based on. They may then create multiple definitions (JobDetails) of the job, such as "SalesReportForJoe" and "SalesReportForMike" which have "joe" and "mike" specified in the corresponding JobDataMaps as input to the respective jobs.

When a trigger fires, the JobDetail (instance definition) it is associated to is loaded, and the job class it refers to is instantiated via the JobFactory configured on the Scheduler. The default JobFactory simply calls the default constructor of the job class using Activator.CreateInstance, then attempts to call setter properties on the class that match the names of keys within the JobDataMap. You may want to create your own implementation of JobFactory to accomplish things such as having your application‘s IoC or DI container produce/initialize the job instance.

当触发器被触发的时候,通过Scheduler中配置的JobFactory来实例化与之关联的Job类。缺省的JobFactory只是简单地对Job类调用GetScheduler ()方法。创建自己JobFactory可以利用应用中诸如Ioc或者DI容器所产生或者初始化的Job实例。

In "Quartz speak", we refer to each stored JobDetail as a "job definition" or "JobDetail instance", and we refer to a each executing job as a "job instance" or "instance of a job definition". Usually if we just use the word "job" we are referring to a named definition, or JobDetail. When we are referring to the class implementing the job interface, we usually use the term "job type".

在"Quartz speak",我们将每个存储的 JobDetail 称为"作业定义"或"JobDetail 实例",我们指每个执行中的工作作为"作业实例"或"作业定义实例"。通常如果我们只是使用"工作"一词我们指一个命名的定义或 JobDetail。当我们指实现工作接口的类时,我们通常使用术语"工作类型"。

Job State and Concurrency

Now, some additional notes about a job‘s state data (aka JobDataMap) and concurrency. There are a couple attributes that can be added to your Job class that affect Quartz‘s behaviour with respect to these aspects.

现在,一些附加的说明关于工作状态数据 (aka JobDataMap) 和并发性。有几个属性可以添加到您的工作类影响石英的行为在这些方面。

DisallowConcurrentExecution is an attribute that can be added to the Job class that tells Quartz not to execute multiple instances of a given job definition (that refers to the given job class) concurrently. Notice the wording there, as it was chosen very carefully. In the example from the previous section, if "SalesReportJob" has this attribute, than only one instance of "SalesReportForJoe" can execute at a given time, but it can execute concurrently with an instance of "SalesReportForMike". The constraint is based upon an instance definition (JobDetail), not on instances of the job class. However, it was decided (during the design of Quartz) to have the attribute carried on the class itself, because it does often make a difference to how the class is coded.

DisallowConcurrentExecution 是一个属性,可以添加到工作类告诉Quartz不并发地执行给定的作业定义 (是指给定的工作类) 。请注意这里谨慎的措辞。在前一节的示例如果"SalesReportJob"具有此属性,比只有一个实例的"SalesReportForJoe"可以执行在给定的时间,但它可以执行与"SalesReportForMike"的一个实例。约束基于实例定义(JobDetail) 不工作类的实例。然而,它被决定 (在设计过程中的石英) 具有属性进行类本身,因为它确实时常令到类如何编码的差异。

PersistJobDataAfterExecution is an attribute that can be added to the Job class that tells Quartz to update the stored copy of the JobDetail‘s JobDataMap after the Execute() method completes successfully (without throwing an exception), such that the next execution of the same job (JobDetail) receives the updated values rather than the originally stored values. Like theDisallowConcurrentExecution attribute, this applies to a job definition instance, not a job class instance, though it was decided to have the job class carry the attribute because it does often make a difference to how the class is coded (e.g. the ‘statefulness‘ will need to be explicitly ‘understood‘ by the code within the execute method).

If you use the PersistJobDataAfterExecution attribute, you should strongly consider also using the DisallowConcurrentExecution attribute, in order to avoid possible confusion (race conditions) of what data was left stored when two instances of the same job (JobDetail) executed concurrently.

Other Attributes Of Jobs

Here‘s a quick summary of the other properties which can be defined for a job instance via the JobDetail object:

  • Durability - if a job is non-durable, it is automatically deleted from the scheduler once there are no longer any active triggers associated with it. In other words, non-durable jobs have a life span bounded by the existence of its triggers.
  • RequestsRecovery - if a job "requests recovery", and it is executing during the time of a ‘hard shutdown‘ of the scheduler (i.e. the process it is running within crashes, or the machine is shut off), then it is re-executed when the scheduler is started again. In this case, the JobExecutionContext.Recovering property will return true.

JobExecutionException

Finally, we need to inform you of a few details of the IJob.Execute(..) method. The only type of exception that you should throw from the execute method is the JobExecutionException. Because of this, you should generally wrap the entire contents of the execute method with a ‘try-catch‘ block. You should also spend some time looking at the documentation for the JobExecutionException, as your job can use it to provide the scheduler various directives as to how you want the exception to be handled.

时间: 2024-08-10 17:20:46

Quartz.NET笔记(三) More About Jobs & JobDetails的相关文章

Quartz学习笔记

什么是job schedule system? job schedule system是负责在预定义的时间执行或者通知某个应用组件的系统.举个例子来说,比如在每周一早上9:30发送email通知客户最新的业务情况. java.util.Timer和java.util.TimerTask Timer和TimerTask是可以完成job schedule的两个jdk提供的类,不过这不能称为一个system.Timer和TimerTask是很简单的,不直接支持持久化任务,线程池和类似日历(calend

Caliburn.Micro学习笔记(三)----事件聚合IEventAggregator和 Ihandle&lt;T&gt;

Caliburn.Micro学习笔记(三)----事件聚合IEventAggregator和 Ihandle<T> 今天 说一下Caliburn.Micro的IEventAggregator和IHandle<T>分成两篇去讲这一篇写一个简单的例子 看一它的的实现和源码 下一篇用它们做一个多语言的demo 这两个是事件的订阅和广播,很强大,但用的时候要小心发生不必要的冲突. 先看一下它的实现思想 在Caliburn.Micro里EventAggregator要以单例的形式出现这样可以

构建之法阅读笔记三—结对编程

构建之法阅读笔记三——结对编程 何谓结对编程,结对编程就是程序员肩并肩,平等的,互补的进行开发工作,他们使用同一台电脑,编写同样的程序,一起分析,一起设计,一块交流想法. 然而我以前却并不是这样做的,我以前喜欢在没人打扰的环境下写代码,我觉得有人在我身边看着,会影响我的思路,还有我个人自尊心比较强,不太喜欢被人指指点点,所以每次都是,我写完代码之后,自己先找自己的bug,每当自己实在找不到之后,才会请教大神,但是有时候可能由于自己的能力不足,往往一个很简单的问题,我自己发现就会花费很久的时间,让

3. 蛤蟆的计算机组成原理笔记三系统总线

3. 蛤蟆的计算机组成原理笔记三系统总线 本篇名言:"公正,一定会打倒那些说假话和假作证的人. --赫拉克利特" 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47988545 1.  总线 总线是连接各个部件的信息传输线,是 各个部件共享的传输介质. 1.1             面向CPU 的双总线结构框图 1.2             单总线结构框图 1.3             以存储器为中心的双总线

OpenCV for Python 学习笔记 三

给源图像增加边界 cv2.copyMakeBorder(src,top, bottom, left, right ,borderType,value) src:源图像 top,bottem,left,right: 分别表示四个方向上边界的长度 borderType: 边界的类型 有以下几种: BORDER_REFLICATE # 直接用边界的颜色填充, aaaaaa | abcdefg | gggg BORDER_REFLECT # 倒映,abcdefg | gfedcbamn | nmabcd

NFC学习笔记——三(在windows操作系统上安装libnfc)

本篇翻译文章: 这篇文章主要是说明如何在windows操作系统上安装.配置和使用libnfc. 一.基本信息 1.操作系统: Windows Vista Home Premium SP 2 2.硬件信息: System: Dell Inspiron 1720 Processor: Intel Core 2 Duo CPU T9300 @ 2.5GHz 2.5GHz System type: 32-bit Operating System 3.所需软件: 在windows操作系统上安装软件需要下列

swift学习笔记(三)关于拷贝和引用

在swift提供的基本数据类型中,包括Int ,Float,Double,String,Enumeration,Structure,Dictionary都属于值拷贝类型. 闭包和函数同属引用类型 捕获则为拷贝.捕获即定义这些常量和变量的原作用域已不存在,闭包仍然可以在闭包函数体内引用和修改这些值 class属于引用类型. Array的情况稍微复杂一些,下面主要对集合类型进行分析: 一.关于Dictionary:无论何时将一个字典实例赋给一个常量,或者传递给一个函数方法时,在赋值或调用发生时,都会

《你必须知道的.NET》读书笔记三:体验OO之美

一.依赖也是哲学 (1)本质诠释:"不要调用我们,我们会调用你" (2)依赖和耦合: ①无依赖,无耦合: ②单向依赖,耦合度不高: ③双向依赖,耦合度较高: (3)设计的目标:高内聚,低耦合. ①低耦合:实现最简单的依赖关系,尽可能地减少类与类.模块与模块.层次与层次.系统与系统之间的联系: ②高内聚:一方面代表了职责的统一管理,一方面又代表了关系的有效隔离: (4)控制反转(IoC):代码的控制器交由系统控制而不是在代码内部,消除组件或模块间的直接依赖: (5)依赖注入(DI): ①

老男孩培训视频听课笔记三(在51cto上听的)

SSH 连接Linux工具CRT SSH概念: 现在有两个版本的SSH1/SSH2,建议选择SSH2 查看服务端启动情况:$netstat -lntup | grep 22 自己加的:现在CRT工具很多:crt xshell putty ,现在我使用的是xshell           另外在在centos系统里可以安装lrzsz的软件包,可以实现在crt里利用rz/sz上传/下载小文件,大文件容易出错           CRT连接经常出现的问题:              ·超时问题:利用p

加壳学习笔记(三)-简单的脱壳思路&amp;调试思路

首先一些windows的常用API: GetWindowTextA:以ASCII的形式的输入框 GetWindowTextW:以Unicaode宽字符的输入框 GetDlgItemTextA:以ASCII的形式的输入框 GetDlgItemTextW:以Unicaode宽字符的输入框 这些函数在使用的时候会有些参数提前入栈,如这函数要求的参数是字符串数目.还有大小写啦之类的东西,这些东西是要在调用该函数之前入栈,也就是依次push,就是说一般前面几个push接着一个call,那前面的push可能