如何使用Spring boot在集群内只执行一次计划任务?

如何使用Spring boot在集群内只执行一次计划任务?,spring,spring-boot,cron,locking,scheduled-tasks,Spring,Spring Boot,Cron,Locking,Scheduled Tasks,在我的web应用程序中,我有一个使用spring boot开发的计划任务。 我在tomcat集群上运行它,因此在X小时,计划的任务从每个节点开始 我读到了:,所以我遵循了指南,但它不起作用。。以下是我所做的: 我在pom中包含了这些依赖项: <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-spring<

在我的web应用程序中,我有一个使用spring boot开发的计划任务。 我在tomcat集群上运行它,因此在X小时,计划的任务从每个节点开始

我读到了:,所以我遵循了指南,但它不起作用。。以下是我所做的:

我在pom中包含了这些依赖项:

  <dependency>
        <groupId>net.javacrumbs.shedlock</groupId>
        <artifactId>shedlock-spring</artifactId>
        <version>0.18.2</version>
    </dependency>       
    <dependency>
        <groupId>net.javacrumbs.shedlock</groupId>
        <artifactId>shedlock-provider-jdbc</artifactId>
        <version>0.18.2</version>
    </dependency>
然后在配置数据源的地方:

@Configuration
@EnableJpaRepositories(basePackages = {"it.repository"}, entityManagerFactoryRef="entityManager", transactionManagerRef="transactionManager")
public class DataSourceMuxConfig {

    @Autowired
    private Environment environment;

    @Primary
    @Bean(name = "dataSource")
    @ConfigurationProperties(prefix = "spring.datasource.mux")
    public DataSource dataSource() throws NamingException {
        if(Arrays.asList(environment.getActiveProfiles()).contains("dev")) {
            return DataSourceBuilder.create().build();
        }else {
            Context ctxConfig = new InitialContext();
            return (DataSource) ctxConfig.lookup("java:comp/env/jdbc/mux");
        }
    }

    @Bean
    public LockProvider lockProvider(DataSource dataSource) {
        return new JdbcLockProvider(dataSource);
    }
这是我的日程安排:

@Configuration
@EnableScheduling
@EnableAsync
public class SchedulerConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
    }

    @Bean(destroyMethod = "shutdown")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(10);
    }

    @Bean
    public ScheduledLockConfiguration taskScheduler(LockProvider lockProvider) {
        return ScheduledLockConfigurationBuilder
            .withLockProvider(lockProvider)
            .withPoolSize(10)
            .withDefaultLockAtMostFor(Duration.ofMinutes(10))
            .build();
    }

}
但它不起作用

集群的每个节点同时执行此计划任务。 为什么?


如何避免使用spring boot同时执行多个任务?

我最近实现了一个简单的注释库,在多个节点上只执行一次计划任务。您可以简单地执行以下操作

@Scheduled(cron = "59 59 8 * * *" /* Every day at 8:59:59am */)
@TryLock(name = "emailLock", owner = NODE_NAME, lockFor = TEN_MINUTE)
public void sendEmails() {
  List<Email> emails = emailDAO.getEmails();
  emails.forEach(email -> sendEmail(email));
}
@计划(cron=“59 59 8***”/*每天上午8:59:59*/)
@TryLock(name=“emailLock”,owner=NODE\u name,lockFor=十分钟)
公众电邮(电邮){
List emails=emailDAO.getEmails();
emails.forEach(email->sendmail(email));
}

有关完整配置,请参阅。

您的
锁在哪里至少有一个
?如果这项工作完成得足够快,理论上可以运行两个。@DarrenForsyth我会添加它,但我的任务持续10分钟。。也许更多确保锁定它的时间最短,你会想要1run@DarrenForsythe我只希望它被执行一次。。所以我添加了至少=10000的锁。。。为了测试它,我创建了另一个具有相同注释的计划任务,但它们同时启动。您是否尝试过同一应用程序的多个实例来运行完全相同的计划任务。我还将检查事务+shedlock代理是否与执行相冲突
@Scheduled(cron = "59 59 8 * * *" /* Every day at 8:59:59am */)
@TryLock(name = "emailLock", owner = NODE_NAME, lockFor = TEN_MINUTE)
public void sendEmails() {
  List<Email> emails = emailDAO.getEmails();
  emails.forEach(email -> sendEmail(email));
}