Quartz架构Q - 或多或少的工作

时间:2014-11-11 16:48:21

标签: java multithreading quartz-scheduler

我正在转换我的Tomcat应用程序以使用Quartz调度程序。我主要用它来触发后台的电子邮件进程,我担心处理器会出现并发作业。所以这是一个最佳实践问题。

问)产生一个石英作业(例如每小时)并让它连续调用几个例程是否更好?这样,例程2将在例程1完成之前启动。

或者最好将每个例程安排为单独的Quartz作业并限制线程数?

如果有更多作业安排线程可用,会发生什么。他们只是排队吗?即可以是我的控制机制。我已经使用指令来防止并发相同的工作。

我不希望同时运行三个类似的作业。它不依赖于时间,因此在处理器上更容易连接。

最直接的架构是什么?

@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class HourJob implements Job, InterruptableJob {

    boolean interrupted = false;        
    String cls = this.getClass().getName();

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {

        System.out.println(cls+"-Start");

        for(int i=1; i<15; i++){            

            try { //do work
                Thread.sleep(1000);
            } catch (InterruptedException e) {  
                e.printStackTrace();
            }

            if(interrupted){
                System.out.println(cls+"-Interrupted");
                return;
            }

        }//for

        System.out.println(cls+"-Exit"); 

    }

    @Override
    public void interrupt() throws UnableToInterruptJobException {
        interrupted = true;     
    }

}

public void contextInitialized(ServletContextEvent event) {

...

sched = schedFact.getScheduler();
sched.start();

JobDetail hourJob  = newJob(HourJob.class ).withIdentity("hourJob",  "group1").build();

Trigger hourTrig = newTrigger()  
    .withIdentity("hourTrig", "group1")  
    .withSchedule(cronSchedule("0 0 * * * ?")).build();

sched.scheduleJob(hourJob, hourTrig);

public void contextDestroyed(ServletContextEvent event) {

...

for(JobExecutionContext job : sched.getCurrentlyExecutingJobs()){
    JobKey jK = job.getJobDetail().getKey(); 
    System.out.printf("Inerrupting %s\n", jK.getName());
    sched.interrupt(jK);
}
sched.shutdown(true);

2 个答案:

答案 0 :(得分:1)

  • 从设计的角度来看,我建议将每个例程作为一个单独的石英工作,如果从概念上讲它们是独立的。这样,如果在运行期间其中一个出现错误,其他执行和完成状态将不会受到影响,如果您需要任何其他等,您将能够单独应用事件监听器。此外,您将能够控制每一个和#39;独立安排。
  • 根据石英文件:
  

如果你只有一些工作每天开几次,那么一个   线程很充足。如果你有成千上万的工作,有很多   每分钟开火,然后你想要一个更像50或100的线程数   (这在很大程度上取决于你的工作所做的工作的性质,   和您的系统资源

因此,您只能使用一个线程,并安排您的作业使用单独的计划执行,以便它们不会同时触发所有。

  • 但是,如果同时发生多个作业尝试运行并且您配置的线程数少于这些作业的数量,那么找不到线程的线程将被视为失效:< / LI>
  

如果持久触发器错过其触发时间,则会发生失火   因为调度程序正在关闭,或者因为没有   Quartz的线程池中可用的线程,用于执行作业。

请注意,您可以通过更改默认失火阈值(30秒)来配置触发器配置错误的时间。如果线程在该阈值之前变为可用,则触发器将执行而不会被视为失效。另一方面,关于失火的触发器,失火策略决定了将会发生什么:

  

不同的触发类型具有不同的失火指令   可供他们使用。默认情况下,他们使用智能策略&#39;指示 -   它具有基于触发器类型和配置的动态行为。   当调度程序启动时,它会搜索任何持久触发器   那些已经失误,然后根据他们的情况更新每一个   单独配置的失火指令。

默认策略对于每种类型的触发器都是不同的,但是一旦线程可用,它通常会运行错过的触发器。在任何情况下,您都需要查看您使用的触发器的策略,并将其更改为您想要的触发器

答案 1 :(得分:0)

这是间接答案,但这就是我们所做的:
由于我们使用Quartz来安排许多类型的任务,我们并不希望某项工作占用大量资源,从而影响其他工作。

所以我们最终分裂了这个过程:
* Quartz作业只是将数据推送到作业队列(每个作业类型不同)
*我们配置执行服务(轻松扩展)从队列中读取并执行实际工作(无论是发送电子邮件还是其他批处理操作)。

我们现在有超过数千个作业在没有并发问题的情况下运行,并且能够轻松扩展每种作业类型