有关通过使用ShedLock让ThreadPoolTask​​Scheduler处理多个计划任务的分布式锁定的问题

时间:2019-08-28 11:20:07

标签: spring-boot shedlock

我知道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;
    }
}

2 个答案:

答案 0 :(得分:0)

我终于想出了一种完成查询的方法。与其使用@SchedulerLock批注,不如使用自定义的LockConfigurationExtractor将TaskScheduler包装到LockableTaskScheduler,并手动调度每个taskScheduler,如下所示:

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

答案 1 :(得分:0)

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

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);
}