Spring Boot中如何配置Quartz确保任务同一时间仅执行一次?
确保Quartz任务同一时间仅执行一次的配置方案
针对你的场景(支持cron调度+手动触发,@DisallowConcurrentExecution不足以满足需求),可以从以下几个层面入手解决:
1. 单节点场景:正确结合Quartz注解
首先确保Job类正确使用注解组合,覆盖Quartz调度层面的并发控制:
@DisallowConcurrentExecution:阻止Quartz为同一个JobDetail实例调度多个并发执行的任务,但仅当所有触发(包括手动)都通过Quartz调度器触发时生效。@PersistJobDataAfterExecution:配合前者使用,确保JobDataMap的状态在执行后持久化,避免并发判断逻辑失效。
示例代码:
@DisallowConcurrentExecution @PersistJobDataAfterExecution public class YourQuartzJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { // 任务执行逻辑 } }
注意:如果手动触发是直接调用Job的execute方法(而非通过Quartz的Scheduler.triggerJob()),该注解组合将失效,因为绕开了Quartz的调度控制。
2. 手动触发前强制检查任务运行状态
如果手动触发是通过业务代码发起,必须先检查当前任务是否正在执行,再决定是否触发:
通过Quartz的Scheduler API获取实时执行状态:
@Autowired private Scheduler scheduler; public boolean triggerJobManually(String jobName, String jobGroup) throws SchedulerException { JobKey jobKey = new JobKey(jobName, jobGroup); // 检查当前是否有该任务的实例正在执行 List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs(); for (JobExecutionContext ctx : executingJobs) { if (ctx.getJobDetail().getKey().equals(jobKey)) { return false; // 任务正在执行,拒绝触发 } } // 手动触发任务 scheduler.triggerJob(jobKey); return true; }
3. 分布式场景:引入分布式锁
如果项目是多节点部署,仅靠Quartz自身注解无法跨节点控制并发,需要引入分布式锁(如Redis):
在Job的execute方法开头添加锁逻辑,确保同一时间只有一个节点能执行任务:
@DisallowConcurrentExecution @PersistJobDataAfterExecution public class YourDistributedQuartzJob implements Job { @Autowired private StringRedisTemplate redisTemplate; private static final String LOCK_KEY = "quartz:job:your_job_lock"; // 锁超时时间需大于任务最长预估执行时间 private static final long LOCK_TIMEOUT = 30000; @Override public void execute(JobExecutionContext context) throws JobExecutionException { // 尝试获取分布式锁 Boolean lockAcquired = redisTemplate.opsForValue() .setIfAbsent(LOCK_KEY, "locked", LOCK_TIMEOUT, TimeUnit.MILLISECONDS); if (lockAcquired == null || !lockAcquired) { // 未获取到锁,说明任务正在执行,直接返回 return; } try { // 任务执行逻辑 } finally { // 执行完成后释放锁 redisTemplate.delete(LOCK_KEY); } } }
4. 集群模式下配置Quartz JobStore
如果使用Quartz集群部署,需配置基于数据库的JobStore,确保任务状态在集群节点间同步:
在application.yml中添加配置:
spring: quartz: job-store-type: jdbc properties: org: quartz: scheduler: instanceId: AUTO jobStore: class: org.quartz.impl.jdbcjobstore.JobStoreTX driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate tablePrefix: QRTZ_ isClustered: true clusterCheckinInterval: 10000
集群模式下,Quartz会通过数据库锁确保同一任务不会在多个节点同时执行,配合@DisallowConcurrentExecution可实现更可靠的并发控制。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

