How can I execute only once a scheduled task inside a cluster using Spring boot?
Asked Answered
P

1

6

I have a scheduled task in my web-app developed using spring boot. I run it on a tomcat cluster, so at hour X the scheduled task start from every node.

I read about: https://github.com/lukas-krecan/ShedLock, so I followed the guide, but it doesn't work.. Here what I have done:

I included these dependency in my 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>

Then I added this to my method:

@Transactional(value="transactionManagerClienti",readOnly=false)
@Scheduled(cron="0 03 7,10,13,15 * * MON-FRI")
@SchedulerLock(name = "syncCliente"
@Override
public void syncCliente() {
  ....
}

then where I config the datasource I did:

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

and this my schedule config:

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

}

but it doesn't work.

Each node of the cluster excute at the same time this scheduled task. Why?

How can I avoid to execute multiple times a task at the same time with spring boot?

Punctate answered 11/4, 2018 at 11:7 Comment(7)
wheres your lock-for-at-least? If that job completes quick enough two could theoretically run.Hoopoe
@DarrenForsythe I'll add it, but my task lasts 10 minutes.. maybe morePunctate
make sure to lock it for the minimum amount of time you would want 1 runHoopoe
@DarrenForsythe I want that only once it will be exectued.. So I added lock-for-at-least=10000... To test it I create another scheduled task, with the same annotation, but they start at the same time.Punctate
and have you tried multiple instances of the same application trying to run the exact same schedule task. I'd also check if the transactional + shedlock proxying is interferring with the executionHoopoe
@DarrenForsythe, yes of course.. at the moment, I'm trying multiple instances of the same application trying to run the exact same schedule task on 2 different tomcat node (2 different server)Punctate
Do you have primary key on the table?Devolve
T
1

Very late answer, but it seems you are missing the annotation EnableSchedulerLock. Without that annotation all instances will run the scheduling without any locking.

Therapeutics answered 20/8, 2022 at 6:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.