Quartz 2.2多调度器和@DisallowConcurrentExecution

3
请看这个例子。
一个示例Web应用程序在启动时调用`scheduler.start()`。调度程序配置为将其作业存储在数据库中。
该应用程序被复制到了六个Web服务器上。
因此,如果我们启动六个Web服务器,我们将在单个DB上拥有六个具有相同名称的调度程序。如https://quartz-scheduler.org/documentation/quartz-2.1.x/cookbook/MultipleSchedulers中所述:

不要启动(scheduler.start())非集群实例,它会针对正在运行(start()ed)与相同调度程序名称相同的任何其他实例使用相同的数据库表集。您可能会遇到严重的数据损坏,并且肯定会经历不稳定的行为。

所以这将失败。
我的问题是,如果我确定我的所有作业都具有`@DisallowConcurrentExecution`,那么上面的方法是否有效,还是仍然会失败?!
如果`@DisallowConcurrentExecution`无法帮助,我应该手动配置一个服务器来作为主服务器。
public class StartUp implements ServletContextListener {

   public void contextInitialized(ServletContextEvent event) {
       if(THIS_IS_MASTER_TOMCAT){
         scheduler.start()
       }
}

有更好的方法吗?!

3
DisallowConcurrentExecution 只能防止同一个节点上运行您的类两次。当您只在一个节点上启动调度程序时,该节点将是唯一的调度程序。您需要设置一个 Quartz 集群,每个调度程序都有唯一的名称。可以让 Quartz 在启动时生成节点名称。我不完全确定这一切,因为我的上一个使用 Quartz 的项目是很久以前,但它是集群化的 ;) - Rene M.
1个回答

6
基本上,Rene M.是正确的。以下是涉及Quartz的相关文档:

http://www.quartz-scheduler.org/documentation/quartz-2.2.x/configuration/ConfigJDBCJobStoreClustering.html

现在先来介绍一下我们公司的背景和一个概念性的例子。我们在 Wildfly 集群中使用 Quartz 集群模式。也就是说,每个 Wildfly 集群节点都运行着 Quartz。由于 Quartz 本身在集群模式下运行,并且指向同一个数据库架构,我们保证了每个集群只会运行一个作业。详见文档。关键问题如下:
  1. 单个 Quartz 集群必须针对单个 Quartz 数据库架构运行。你需要按照文档创建关系型数据库表,这不是什么大问题。
  2. 你必须正确设置 quartz.property 文件,并且每个集群节点上都必须存在该文件的副本。而且这些文件必须完全相同。
  3. 最后,你必须使用 NonJTA 数据源,否则 Quartz 集群将无法正常工作。在 Wildfly 环境下,这通常意味着 Quartz 需要自己的数据源。
下面是 quartz.property 的示例:
    #============================================================================
# Configure Main Scheduler Properties 
#============================================================================

org.quartz.scheduler.instanceName = BjondScheduler
org.quartz.scheduler.instanceId = AUTO

#============================================================================
# Configure ThreadPool 
#============================================================================

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5

#============================================================================
# Configure JobStore 
#============================================================================

org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreCMT
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 5000

org.quartz.scheduler.wrapJobExecutionInUserTransaction = true
org.quartz.scheduler.userTransactionURL = java:jboss/UserTransaction

org.quartz.jobStore.dataSource = PostgreSQLDS
org.quartz.jobStore.nonManagedTXDataSource = PostgreSQLDSNoJTA

org.quartz.dataSource.PostgreSQLDSNoJTA.jndiURL=java:jboss/datasources/PostgreSQLDSNoJTA
org.quartz.dataSource.PostgreSQLDS.jndiURL=java:jboss/datasources/PostgreSQLDS


#============================================================================
# Configure Logging
#============================================================================
#org.quartz.plugin.jobHistory.class=org.quartz.plugins.history.LoggingJobHistoryPlugin
#org.quartz.plugin.jobHistory.jobToBeFiredMessage=Bjond Job [{1}.{0}] to be fired by trigger [{4}.{3}] at: {2, date, HH:mm:ss MM/dd/yyyy} re-fire count: {7}
#org.quartz.plugin.jobHistory.jobSuccessMessage=Bjond Job [{1}.{0}] execution complete and reports: {8}
#org.quartz.plugin.jobHistory.jobFailedMessage=Bjond Job [{1}.{0}] execution failed with exception: {8}
#org.quartz.plugin.jobHistory.jobWasVetoedMessage=Bjond Job [{1}.{0}] was vetoed. It was to be fired by trigger [{4}.{3}] at: {2, date, dd-MM-yyyy HH:mm:ss.SSS}

现在我们在 standalone.xml 中的数据源片段:

            <datasource jta="false" jndi-name="java:jboss/datasources/PostgreSQLDSNoJTA" pool-name="PostgreSQLDSNoJTA" enabled="true" use-java-context="true" use-ccm="true">

你需要根据自己的要求填写此数据源元素。@DisallowConcurrentExecution 是一个不错的想法,可以防止单个节点上的多个作业执行特定方法,但是它是石英集群防止同一作业在多个 VM 上运行;而不是这个注释。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接