返回

无法执行的Quartz任务:原因与解决方案

后端

Quartz与Spring Boot:作业中断后如何保证作业执行?

在使用Quartz与Spring Boot集成时,如果作业在执行过程中被中断,例如应用程序重新启动,则在应用程序重新启动后,该作业将无法继续执行。本文将探讨造成这种情况的原因并提供两种解决方案,帮助您解决Quartz在Spring Boot项目中重启后无法继续执行作业的问题。

原因:MisfireInstruction.DO_NOTHING

Quartz提供了多种MisfireInstruction选项,用于指定在遇到已过期的触发器时应采取的操作。其中,MisfireInstruction.DO_NOTHING表示不采取任何行动,这是Quartz的默认设置。当作业被中断后,Quartz会将触发器标记为已过期。在应用程序重新启动后,Quartz会根据触发器的配置重新调度作业,但由于MisfireInstruction设置为DO_NOTHING,因此Quartz不会采取任何行动,导致作业无法继续执行。

解决方案一:修改MisfireInstruction设置

要解决此问题,可以在Spring Boot应用程序中配置Quartz的MisfireInstruction。在application.properties文件中,将quartz.jobStore.misfireThreshold值设置为大于10000(10秒)。这将确保在作业被中断超过10秒后,Quartz会自动重新执行该作业。

解决方案二:使用JobStore

也可以配置Quartz使用JobStore来持久化作业状态。JobStore可以将作业的状态保存在数据库中,以便在应用程序重新启动后恢复作业的状态。在application.properties文件中,可以配置Quartz使用JobStore,如下所示:

spring.quartz.job-store-type=jdbc
spring.datasource.url=jdbc:mysql://localhost:3306/quartz
spring.datasource.username=quartz
spring.datasource.password=quartz

示例代码

以下是在Spring Boot应用程序中使用Quartz的示例代码:

import org.quartz.*;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class QuartzApplication {

    public static void main(String[] args) {
        SpringApplication.run(QuartzApplication.class, args);
    }

    @Bean
    public JobDetail jobDetail() {
        return JobBuilder.newJob(MyJob.class)
                .withIdentity("myJob", "myGroup")
                .build();
    }

    @Bean
    public Trigger trigger(JobDetail jobDetail) {
        return TriggerBuilder.newTrigger()
                .forJob(jobDetail)
                .withIdentity("myTrigger", "myGroup")
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(10)
                        .repeatForever())
                .build();
    }

    public static class MyJob implements Job {

        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            System.out.println("Hello Quartz!");
        }
    }
}

常见问题解答

  • 为什么Quartz的默认MisfireInstruction设置为MisfireInstruction.DO_NOTHING?

    为了防止作业重复执行。如果作业在执行过程中被中断,而MisfireInstruction设置为立即重新执行作业,则作业可能会被重复执行,从而导致意外结果。

  • MisfireInstruction选项都有哪些?

    Quartz提供了多种MisfireInstruction选项,包括:

    • MisfireInstruction.DO_NOTHING:不采取任何行动。
    • MisfireInstruction.SMART_POLICY:采用智能策略,在作业执行超过misfireThreshold的时间后重新执行作业。
    • MisfireInstruction.FIRE_ONCE_NOW:立即重新执行作业。
    • MisfireInstruction.IGNORE_MISFIRES:忽略已过期的触发器。
  • JobStore支持哪些数据库?

    Quartz支持多种数据库,包括:

    • MySQL
    • PostgreSQL
    • Oracle
    • SQL Server
    • MongoDB
  • 如何配置Quartz使用JobStore?

    可以在application.properties文件中配置Quartz使用JobStore,如下所示:

    spring.quartz.job-store-type=jdbc
    spring.datasource.url=jdbc:mysql://localhost:3306/quartz
    spring.datasource.username=quartz
    spring.datasource.password=quartz
    
  • Quartz作业是否可以在应用程序重新启动后恢复执行?

    是的,如果您配置Quartz使用JobStore,则作业的状态将保存在数据库中,并在应用程序重新启动后恢复执行。