Quartz_2.2.X学习系列二十四:Quartz Best Practices

Quartz Best Practices

 

Best Practices

Best Practices

 

Production System Tips

Skip Update Check

Quartz contains an “update check” feature that connects to a server to check if there is a new version of Quartz available for download. This check runs asynchronously and does not affect startup/initialization time of Quartz, and it fails gracefully if the connection cannot be made. If the check runs, and an update is found, it will be reported as available in Quartz’s logs.

You can disable the update check with the Quartz config property “org.quartz.scheduler.skipUpdateCheck: true” or the system property “org.terracotta.quartz.skipUpdateCheck=true” (which you can set in your system environment or as a -D on the java command line). It is recommended that you disable the update check for production deployments.

 

JobDataMap Tips

Only Store Primitive Data Types (including Strings) In the JobDataMap

Only store primitive data types (including Strings) in JobDataMap to avoid data serialization issues short and long-term.

只在JobDataMap中存储原始数据类型(包括字符串),以避免数据序列化问题的短期和长期问题。

 

Use the Merged JobDataMap

The JobDataMap that is found on the JobExecutionContext during Job execution serves as a convenience. It is a merge of the JobDataMap found on the JobDetail and the one found on the Trigger, with the value in the latter overriding any same-named values in the former.

Storing JobDataMap values on a Trigger can be useful in the case where you have a Job that is stored in the scheduler for regular/repeated use by multiple Triggers, yet with each independent triggering, you want to supply the Job with different data inputs.

In light of all of the above, we recommend as a best practice the following: Code within the Job.execute(..) method should generally retrieve values from the JobDataMap on found on the JobExecutionContext, rather than directly from the one on the JobDetail.

 

在作业执行期间,在JobExecutionContext中找到的JobDataMap是很方便的。它是在JobDetail中找到的JobDataMap和触发器上找到的JobDataMap的合并,后者的值会overriding前者中任何同名的值。

如果您有一个存储在调度程序中的Job,并由多个触发器进行定期/重复使用,然而对于每个独立的触发,您想为其Job提供不同的数据输入,那么在触发器中储存JobDataMap值是很有用的。

根据上面的所有内容,我们推荐以下的最佳实践:在Job.execute(..)方法中编写代码通常应该从JobExecutionContext中找到的JobDataMap检索值,而不是直接从JobDetail中检索。因为这样可以直接找到trigger中的JobDataMap中的值。(但注意合并后的JobDataMap不能传值给下次执行的同一个Job

 

Trigger Tips

Use TriggerUtils

TriggerUtils:

  • Offers a simpler way to create triggers (schedules)
  • Has various methods for creating triggers with schedules that meet particular descriptions, as opposed to directly instantiating triggers of a specific type (i.e. SimpleTrigger, CronTrigger, etc.) and then invoking various setter methods to configure them
  • Offers a simple way to create Dates (for start/end dates)
  • Offers helpers for analyzing triggers (e.g. calculating future fire times)

 

TriggerUtils:

  • 提供了一种更简单的方式来创建触发器(时间表)
  • 有各种方法来创建带有特定描述的时间表的触发器,而不是直接实例化特定类型的触发器(例如simple触发器、cron触发器等等),然后调用各种setter方法来配置它们
  • 提供一种简单的方式来创建日期(用于起始/结束日期)
  • 为分析触发器提供帮助(例如,计算未来的触发时间)

 

JDBC JobStore

Never Write Directly To Quartz’s Tables

Writing scheduling data directly to the database (via SQL) rather than using scheduling API:

  • Results in data corruption (deleted data, scrambled data)
  • Results in job seemingly “vanishing” without executing when a trigger’s fire time arrives
  • Results in job not executing “just sitting there” when a trigger’s fire time arrives
  • May result in: Dead-locks
  • Other strange problems and data corruption

 

不要直接写入Quartz的表

将调度数据直接写入数据库(通过SQL),而不是使用调度API:

  • 导致数据腐败(删除数据,搅拌数据)
  • 导致在一个触发器的触发时间到来时,工作似乎正在“消失”,而没有执行。
  • 导致在触发器的触发时间到达时,工作不会执行“只是坐在那里”
  • 可能导致:死锁
  • 其他奇怪的问题和数据损坏

 

Never Point A Non-Clustered Scheduler At the Same Database As Another Scheduler With The Same Scheduler Name

If you point more than one scheduler instance at the same set of database tables, and one or more of those instances is not configured for clustering, any of the following may occur:

  • Results in data corruption (deleted data, scrambled data)
  • Results in job seemingly “vanishing” without executing when a trigger’s fire time arrives
  • Results in job not executing, “just sitting there” when a trigger’s fire time arrives
  • May result in: Dead-locks
  • Other strange problems and data corruption

 

永远不要在同一个数据库中使用相同的调度器名称来指向同一个数据库的非集群调度程序

如果您在同一组数据库表中指向多个调度程序实例,并且其中一个或多个实例没有配置为集群,那么以下任何一种情况都可能发生:

  • 导致数据腐败(删除数据,搅拌数据)
  • 导致在一个触发器的触发时间到来时,工作似乎正在“消失”,而没有执行。
  • 导致在工作中没有执行的结果,“只是坐在那里”,当一个触发器的触发时间到来时
  • 可能导致:死锁
  • 其他奇怪的问题和数据损坏

 

即,在非集群的情况下,使用JDBCStore时,保证只使用一个调度程序即可。

 

Ensure Adequate Datasource Connection Size

It is recommended that your Datasource max connection size be configured to be at least the number of worker threads in the thread pool plus three. You may need additional connections if your application is also making frequent calls to the scheduler API. If you are using JobStoreCMT, the “non managed” datasource should have a max connection size of at least four.

 

确保足够的数据源连接大小

建议将您的数据源最大连接大小配置为至少线程池中的工作者线程数加上3。如果您的应用程序也频繁地调用调度器API,那么您可能需要额外的连接。如果您使用的是JobStoreCMT,那么“非托管”数据源应该具有至少4个最大连接大小。

 

Daylight Savings Time

Avoid Scheduling Jobs Near the Transition Hours of Daylight Savings Time

NOTE: Specifics of the transition hour and the amount of time the clock moves forward or back varies by locale see: https://secure.wikimedia.org/wikipedia/en/wiki/Daylight_saving_time_around_the_world.

SimpleTriggers are not affected by Daylight Savings Time as they always fire at an exact millisecond in time, and repeat an exact number of milliseconds apart.

Because CronTriggers fire at given hours/minutes/seconds, they are subject to some oddities when DST transitions occur.

As an example of possible issues, scheduling in the United States within TimeZones/locations that observe Daylight Savings time, the following problems may occur if using CronTrigger and scheduling fire times during the hours of 1:00 AM and 2:00 AM:

  • 1:05 AM may occur twice! - duplicate firings on CronTrigger possible
  • 2:05 AM may never occur! - missed firings on CronTrigger possible

Again, specifics of time and amount of adjustment varies by locale.

Other trigger types that are based on sliding along a calendar (rather than exact amounts of time), such as CalenderIntervalTrigger, will be similarly affected - but rather than missing a firing, or firing twice, may end up having it’s fire time shifted by an hour.

 

日光节约时制

避免在日光节约时间的过渡时间安排工作

注意:过渡时间的细节和时钟向前或向后移动的时间长短因地区而异:https://secure.wikiedia.org/wikipedi/en/wiki/daylightsavingtimearoundtheworld。

SimpleTriggers不受日光节约时间的影响,因为它们总是在一毫秒内精确地触发,并重复精确的毫秒数。

因为在给定的时间/分钟/秒内,CronTriggers 会触发,当DST发生转换时,它们会受到一些奇怪的影响。

作为可能出现的问题的一个例子,在美国的时间范围内,在观察日光节约时间的时间内,如果使用CronTriggers 并在凌晨1:00和2:00的时间安排触发时间,可能会出现以下问题:

•1:05可能会发生两次!-在CronTrigger 上重复的触发

•2:05可能永远不会发生!-不可能在CronTrigger上触发

同样,时间的细节和调整的数量因地区而异。

其他的触发类型是基于日历上的滑动(而不是精确的时间),比如calenderinterval触发器,也会受到类似的影响——但是,与其错过一次触发,或者两次触发,可能最终会使它的触发时间改变一个小时。

 

 

Jobs

Waiting For Conditions

Long-running jobs prevent others from running (if all threads in the ThreadPool are busy).

If you feel the need to call Thread.sleep() on the worker thread executing the Job, it is typically a sign that the job is not ready to do the rest of its work because it needs to wait for some condition (such as the availability of a data record) to become true.

A better solution is to release the worker thread (exit the job) and allow other jobs to execute on that thread. The job can reschedule itself, or other jobs before it exits.

 

等待条件

长时间运行的作业阻止其他作业运行(如果ThreadPool中的所有线程都很忙)。

如果你觉得需要调用Thread.sleep() 在执行的工作的工作线程中,它通常表明工作还没有准备好做其他的工作,因为它需要等待某个条件(如可用性的数据记录)成为真实。

一个更好的解决方案是释放工作线程(退出作业),并允许其他作业在该线程上执行。这项工作可以在它退出之前重新安排自己的时间,或者其他的工作。

 

Throwing Exceptions

A Job’s execute method should contain a try-catch block that handles all possible exceptions.

If a job throws an exception, Quartz will typically immediately re-execute it (and it will likely throw the same exception again). It’s better if the job catches all exception it may encounter, handle them, and reschedule itself, or other jobs. to work around the issue.

 

抛出异常

作业的execute方法应该包含一个try-catch块,它可以处理所有可能的异常。

如果一个作业抛出异常,Quartz通常会立即重新执行它(并且它可能会再次抛出相同的异常)。如果这个Job抓住了它可能遇到的所有异常,处理它们,重新安排自己,或者其他Jobs,以解决这个问题,这样就更好了。

 

Recoverability and Idempotence

In-progress Jobs marked “recoverable” are automatically re-executed after a scheduler fails. This means some of the job’s “work” will be executed twice.

This means the job should be coded in such a way that its work is idempotent.

 

可恢复性和幂等性

在调度器失败后,标记为“可恢复”的正在进行的作业会自动重新执行。这意味着一些Job的“工作”将被执行两次。这意味着该工作应该以一种使其工作具有幂等性的方式进行编码。

 

幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。

在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“setTrue()”函数就是一个幂等函数,无论多次执行,其结果都是一样的.

 

 

Listeners (TriggerListener, JobListener, SchedulerListener

Keep Code In Listeners Concise And Efficient

Performing large amounts of work is discouraged, as the thread that would be executing the job (or completing the trigger and moving on to firing another job, etc.) will be tied up within the listener.

 

Listeners 中保持代码的简洁和高效

执行大量的工作是不鼓励的,因为执行作业的线程(或完成触发器并继续执行另一个作业等)将被绑定到侦听器中。

 

Handle Exceptions

Every listener method should contain a try-catch block that handles all possible exceptions.

If a listener throws an exception, it may cause other listeners not to be notified and/or prevent the execution of the job, etc.

 

处理异常

每个侦听器方法都应该包含一个try-catch块,它可以处理所有可能的异常。

如果侦听器抛出异常,则可能导致其他侦听器不被通知或/或阻止作业的执行,等等。

 

Exposing Scheduler Functionality Through Applications

Be Careful of Security!

Some users expose Quartz’s Scheduler functionality through an application user interface. This can be very useful, though it can also be extremely dangerous.

Be sure you don’t mistakenly allow users to define jobs of any type they wish, with whatever parameters they wish. For example, Quartz ships with a pre-made job org.quartz.jobs.NativeJob, which will execute any arbitrary native (operating system) system command that it is defined to. Malicious users could use this to take control of, or destroy your system.

 

小心安全!

一些用户通过应用程序用户界面公开Quartz的调度器功能。尽管它也可能非常危险,但这可能非常有用。

要确保您不会错误地允许用户定义他们希望的任何类型的工作,以及他们希望的任何参数。

例如,Quartz附带了一个预先设定好的工作org.quartz.jobs.NativeJob,,它将执行任何任意的本机(操作系统)已被定义好的系统命令。恶意用户可以使用它来控制或破坏您的系统。

 

Likewise other jobs such as SendEmailJob, and virtually any others could be used for malicious intent.

Allowing users to define whatever job they want effectively opens your system to all sorts of vulnerabilities comparable/equivalent to Command Injection Attacks as defined by OWASP and MITRE.

 

From <http://www.quartz-scheduler.org/documentation/best-practices.html>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值