Как я могу выполнить только один раз запланированную задачу внутри кластера с помощью загрузки spring?

У меня есть запланированная задача в моем веб-приложении, разработанном с использованием весенний ботинок. Я запускаю его в кластере tomcat, поэтому в час X запускается запланированная задача с каждого узла.

Я читал о: https://github.com/lukas-krecan/ShedLock, поэтому я последовал руководству, но оно не работает .. Вот что я сделал:

Я включил эти зависимости в свой 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>

Затем я добавил это в свой метод:

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

затем, где я настраиваю источник данных, который я сделал:

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

}

но это не работает.

Каждый узел кластера одновременно выполняет это запланированное задание. Почему?

Как я могу избежать многократного выполнения задачи одновременно с весенней загрузкой?

где твой lock-for-at-least? Если эта работа завершится достаточно быстро, две теоретически могут работать.

Darren Forsythe 11.04.2018 13:58

@DarrenForsythe Я добавлю, но моя задача длится 10 минут .. может и больше

Droide 11.04.2018 14:21

убедитесь, что заблокировали его на минимальное время, на которое вы хотели бы 1 запуск

Darren Forsythe 11.04.2018 14:30

@DarrenForsythe Я хочу, чтобы он был выполнен только один раз. Итак, я добавил блокировку по крайней мере = 10000 ... Чтобы проверить это, я создаю еще одну запланированную задачу с той же аннотацией, но они запускаются в одно и то же время.

Droide 11.04.2018 14:35

и пробовали ли вы несколько экземпляров одного и того же приложения, пытаясь запустить одну и ту же задачу расписания. Я бы также проверил, не мешает ли проксирование транзакций + shedlock выполнению

Darren Forsythe 11.04.2018 14:38

@DarrenForsythe, да, конечно ... на данный момент я пробую несколько экземпляров одного и того же приложения, пытаясь запустить одну и ту же задачу расписания на 2 разных узлах tomcat (2 разных сервера)

Droide 11.04.2018 16:44

У вас есть первичный ключ на столе?

Lukas 30.03.2019 09:26
5
7
2 374
1

Ответы 1

Недавно я реализовал простую библиотеку аннотаций утка для выполнения запланированной задачи только один раз на нескольких узлах. Вы можете просто сделать что-то вроде ниже.

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

Пожалуйста, см. Страница на Github для полной конфигурации.

Другие вопросы по теме