关于使用 ShedLock 让 ThreadPoolTask​​Scheduler 处理多个调度任务的分布式锁的问题

Issue about Distributed lock by using ShedLock to have ThreadPoolTaskScheduler process multiple schedule tasks

我知道 ShedLock 可以用来做与 Spring 集成的分布式锁,如:

    @Scheduled(cron = "*/5 * * * * ?")
    @SchedulerLock(name = "exampleLock", lockAtLeastForString = "20000", lockAtMostForString = "30000")
    private void exampleMethod(){
         System.out.println(String.format("[%s] test job runs...", new Date()));
}

但对于我的情况,我想执行从数据库读取的多个计划任务 (Crons),并由 ThreadPoolTask​​Scheduler 单独独立地处理。我编码如下,但是它不能处理多个实例来执行每个计划任务。 Spring 有没有什么办法可以达到这个目的?任何想法将不胜感激。

public class ExampleShedLock implements SchedulingConfigurer {

    @Resource
    private ScheduleTaskRepository scheduleTaskRepository;

    @Resource
    private TaskScheduler threadPoolTaskScheduler;

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {

        scheduledTaskRegistrar.setTaskScheduler(getThreadPoolTaskScheduler());
        Map<String, String> dataMap = scheduleTaskRepository
                .selectExpressionByIsActive();
        dataMap.forEach(
                (key, expression) -> scheduledTaskRegistrar.getScheduler()
                        .schedule(() -> scheduledTask(),
                                (TriggerContext triggerContext) -> {
                                    CronTrigger trigger = new CronTrigger(
                                            expression,
                                            TimeZone.getTimeZone(ZoneOffset.UTC));
                                    return trigger.nextExecutionTime(triggerContext);
                                }));
    }

    @SchedulerLock(name = "TaskScheduler",
            lockAtLeastFor = 20*1000, lockAtMostFor = 30*1000)
    private void scheduledTask() {

        System.out.println(
                Thread.currentThread().getName() + " - " + Calendar
                        .getInstance()
                        .getTime();

    }


    @Bean(name = "threadPoolTaskScheduler")
    public TaskScheduler getThreadPoolTaskScheduler() {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(10);
        taskScheduler.setThreadNamePrefix("Scheduled-");
        taskScheduler.setRejectedExecutionHandler(new 
        ThreadPoolExecutor.CallerRunsPolicy());
        taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
        taskScheduler.setAwaitTerminationSeconds(60);
        taskScheduler.initialize();
        return taskScheduler;
    }
}

我终于想出了一种方法来完成查询。我可以使用自定义的 LockConfigurationExtractor 将 TaskScheduler 包装到 LockableTaskScheduler 并像这样手动安排每个 taskScheduler,而不是使用 @SchedulerLock 注释:

DefaultLockManager defaultLockManager = new DefaultLockManager(lockProvider,
            customizedLockConfigurationExtractor);
return new LockableTaskScheduler(taskScheduler, defaultLockManager);

您可以创建一个 LockableTaskScheduler 对象并将其设置为 ScheduledTaskRegistrar。这将在每次执行前检查 shedlock table。

public LockableTaskScheduler getScheduler() {
    LockConfigurationExtractor lockConfigurationExtractor = (task) ->  Optional.
                of(new LockConfiguration(Instant.now(), "schedulerJob", Duration.ofMinutes(15), Duration.ofMinutes(5)));
        
        LockManager lockManager = new DefaultLockManager(lockProvider, lockConfigurationExtractor);
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setThreadNamePrefix("MyThreadPoolTaskScheduler");
        scheduler.initialize();
       return new LockableTaskScheduler(scheduler, lockManager);
}