Spring Boot中Quartz重复调度问题:避免应用重启重复创建定时任务
Spring Quartz 避免重复创建Cron任务问题
我有一个Spring Quartz应用,每次启动应用时都会调度Cron任务。我希望当任务已存在时,不再重复创建该Cron任务。
调度代码
@PostConstruct public void assignJobs() throws IOException, SchedulerException { JobDetail jobDetail = JobBuilder.newJob(CollectTransactionDataJob.class) .withIdentity(UUID.randomUUID().toString(), CollectTransactionDataJob.GROUP) .withDescription(CollectTransactionDataJob.DESCRIPTION) .storeDurably() .build(); Trigger trigger = TriggerBuilder.newTrigger() .forJob(jobDetail) .withIdentity(jobDetail.getKey().getName(), CollectTransactionDataJob.TRIGGER_GROUP) .withDescription(CollectTransactionDataJob.TRIGGER_DESCRIPTION) .withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(10, 30)) .build(); Scheduler scheduler = quartzConfig.schedulerFactoryBean().getScheduler(); scheduler.scheduleJob(jobDetail, trigger); }
期望行为
若CRON触发时间为10:30 当前时间为10:00 在10:00至10:30期间应用启动2次 则10:30时,CRON应仅执行1次。
实际行为
10:30时,CRON执行了2次。
Quartz配置
org.quartz.jobStore.class = org.springframework.scheduling.quartz.LocalDataSourceJobStore org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
问题原因
当前代码每次启动时都会用UUID.randomUUID().toString()生成唯一的Job和Trigger名称,结合持久化的LocalDataSourceJobStore,多次启动后会在数据库中创建多个逻辑完全相同的Job和Trigger,到触发时间时所有Trigger都会触发对应的Job,导致重复执行。
解决方案
固定Job和Trigger的唯一标识(name和group),并在调度前检查是否已存在,存在则跳过创建逻辑:
@PostConstruct public void assignJobs() throws IOException, SchedulerException { // 固定Job和Trigger的标识,避免随机生成 String jobName = "collect-transaction-data-job"; String triggerName = "collect-transaction-data-trigger"; JobKey jobKey = new JobKey(jobName, CollectTransactionDataJob.GROUP); TriggerKey triggerKey = new TriggerKey(triggerName, CollectTransactionDataJob.TRIGGER_GROUP); Scheduler scheduler = quartzConfig.schedulerFactoryBean().getScheduler(); // 检查Job是否已存在,不存在则创建 if (!scheduler.checkExists(jobKey)) { JobDetail jobDetail = JobBuilder.newJob(CollectTransactionDataJob.class) .withIdentity(jobKey) .withDescription(CollectTransactionDataJob.DESCRIPTION) .storeDurably() .build(); scheduler.addJob(jobDetail, true); } // 检查Trigger是否已存在,不存在则创建并关联Job if (!scheduler.checkExists(triggerKey)) { Trigger trigger = TriggerBuilder.newTrigger() .forJob(jobKey) .withIdentity(triggerKey) .withDescription(CollectTransactionDataJob.TRIGGER_DESCRIPTION) .withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(10, 30)) .build(); scheduler.scheduleJob(trigger); } }
关键改动说明
- 固定标识:用固定字符串代替随机UUID作为Job和Trigger的name,确保每次启动时检查的是同一个任务实体。
- 存在性检查:通过
scheduler.checkExists()方法判断Job和Trigger是否已在Quartz的JobStore中存在,避免重复创建。 - 拆分调度逻辑:先创建Job(如果不存在),再创建Trigger并关联Job,逻辑更清晰,也避免了原代码中Job和Trigger绑定过紧的问题。
内容的提问来源于stack exchange,提问作者Aditya Rewari
相关产品推荐
相关产品推荐

