ShedLock+SchedulingConfigurer多任务:为每个任务配置独立LockableTaskScheduler
解决ShedLock为每个定时任务配置独立LockableTaskScheduler不生效的问题
问题根源
你这段代码的核心问题在于**ScheduledTaskRegistrar#setTaskScheduler是全局配置方法**,循环中每次调用都会覆盖之前设置的Scheduler,最终所有任务都会使用最后一次初始化的LockableTaskScheduler,导致只有最后一个任务的锁配置能在数据库中生成对应条目。
解决方案
要为每个任务分配独立的锁调度器,不能依赖ScheduledTaskRegistrar的全局Scheduler设置,而是直接用每个任务专属的LockableTaskScheduler来调度任务。修改后的代码如下:
@Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { Map<String, TaskConfig> cronTasks = findJobs(); for (Map.Entry<String, TaskConfig> cronTask : cronTasks.entrySet()) { TaskConfig taskConfig = cronTask.getValue(); LockableTaskScheduler taskSpecificScheduler = getScheduler(taskConfig); // 用当前任务专属的Scheduler直接调度任务 taskSpecificScheduler.schedule(() -> executeTask(taskConfig), taskConfig.getCronTrigger()); log.info("Registering cron task for scheduling: {}, cronExpression: {}", cronTask.getKey(), taskConfig); } } public LockableTaskScheduler getScheduler(TaskConfig value) { LockConfigurationExtractor lockConfigurationExtractor = task -> Optional .of(new LockConfiguration(Instant.now(), value.getConfigEntity().get_id(), Duration.ofMinutes(3), Duration.ofMinutes(2))); LockManager lockManager = new DefaultLockManager(lockProvider, lockConfigurationExtractor); ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); // 给每个调度器的线程前缀加入任务ID,方便日志排查 scheduler.setThreadNamePrefix("TaskScheduler-" + value.getConfigEntity().get_id() + "-"); scheduler.initialize(); return new LockableTaskScheduler(scheduler, lockManager); }
关键说明
- 独立调度器绑定任务:每个任务都使用专属的
LockableTaskScheduler执行,确保锁配置不被覆盖,ShedLock能为每个任务生成独立的数据库锁条目。 - 线程前缀优化:修改线程名前缀加入任务ID,便于后续通过日志定位特定任务的执行情况。
- 资源注意事项:如果任务数量较多,需合理配置
ThreadPoolTaskScheduler的核心线程数、最大线程数等参数,避免系统资源耗尽。 - 锁ID唯一性:确保每个任务的锁ID(即
value.getConfigEntity().get_id())是唯一值,这是ShedLock区分不同任务锁的核心标识。
内容的提问来源于stack exchange,提问作者chaty
相关产品推荐
相关产品推荐

