关于使用 ShedLock 让 ThreadPoolTaskScheduler 处理多个调度任务的分布式锁的问题
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),并由 ThreadPoolTaskScheduler 单独独立地处理。我编码如下,但是它不能处理多个实例来执行每个计划任务。 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);
}
我知道 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),并由 ThreadPoolTaskScheduler 单独独立地处理。我编码如下,但是它不能处理多个实例来执行每个计划任务。 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);
}