Как приостановить запланированное задание, запущенное с помощью аннотации @Scheduled в springboot? - PullRequest
0 голосов
/ 14 июля 2020

У меня есть простая запланированная задача, созданная с помощью аннотации @Scheduled. Что-то вроде этого -

public void doSomething() {
    // My code

}

У меня также есть сине-зеленый сценарий обновления, в котором это запланированное задание потенциально может выполняться как в синем, так и в зеленом кластерах. И учитывая, что эта запланированная задача изменяет БД, существует вероятность того, что один из узлов может перезаписать данные с другого узла - или в худшем случае в условиях гонки.

Я хочу приостановить все запланированные задачи на зеленом кластер, пока он не будет готов принимать трафик c. У меня уже есть код, подключенный к прослушиванию изменений состояния приложения.

Я изучил несколько вариантов -

  1. Просто добавив логическое значение в начале задачи.
  2. Добавление декоратора в ThreadPoolTaskScheduler.

Проблема с этими подходами заключается в том, что они пропускают задачу для этого конкретного расписания и не приостанавливают ее. Итак, если задача пропущена, скажем, в точке T, и приложение запускается немедленно, приложению придется ждать T + 30 минут, чтобы обновить sh данные.

Есть ли способ в springboot приостановить планировщики и возобновить немедленно?

Ответы [ 2 ]

0 голосов
/ 14 июля 2020

Похоже, что изначально Spring не имеет возможности приостанавливать выполнение запланированных задач. Я обычно использую Quartz Scheduler при выполнении задач расписания с помощью spring.

Для этого нам нужно сделать пару конфигураций.

Сначала мы должны настроить наш контекстно-зависимый компонент:

@Component
public final class ApplicationContextHolder extends SpringBeanJobFactory implements ApplicationContextAware {

  private static ApplicationContext context;
  
  private transient AutowireCapableBeanFactory beanFactory;
  
  @Override
  public void setApplicationContext(ApplicationContext ctx) throws BeansException {
    if (context == null) {
      beanFactory = ctx.getAutowireCapableBeanFactory();
      context = ctx;
    }
  }
  
  @Override
  protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
    final Object job = super.createJobInstance(bundle);
    beanFactory.autowireBean(job);
    return job;
  }
  
  /**
   * Get the current application context
   * @return the current context
   */
  public static ApplicationContext getContext() {
    return context;
  }
}

Затем наша конфигурация:

@Configuration
public class QuartzSchedulerConfig {
  
  @Autowired
  private ApplicationContext applicationContext;

  /**
   * Create the job factory bean
   * @return Job factory bean
   */
  @Bean
  public JobFactory jobFactory() {
    ApplicationContextHolder jobFactory = new ApplicationContextHolder();
    jobFactory.setApplicationContext(applicationContext);
    return jobFactory;
  }
  
  /**
   * Create the Scheduler Factory bean
   * @return scheduler factory object
   */
  @Bean
  public SchedulerFactoryBean schedulerFactory() {
    SchedulerFactoryBean factory = new SchedulerFactoryBean();
    factory.setAutoStartup(true);
    factory.setSchedulerName("Scheduler");
    factory.setOverwriteExistingJobs(true);
    factory.setJobFactory(jobFactory());
    return factory;
  }
}

Затем наш фактический сервис:

@Service
public class SchedulerService {

  @Autowired
  private SchedulerFactoryBean schedulerFactory;

  private Scheduler scheduler;
  
  private ScheduledExecutorService executor;

  /**
   * Initialize the scheduler service
   */
  @PostConstruct
  private void init() {
    scheduler = schedulerFactory.getScheduler();
    executor = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
  }

  ...//Other Scheduling tasks can go here

  public void pauseJob(String triggerName, String groupName) {
    TriggerKey tk = new TriggerKey(triggerName, groupName);
    scheduler.pauseJob(tk);
  }
}

Quartz Scheduling дает большую гибкость при планировании задач

http://www.quartz-scheduler.org/overview/

0 голосов
/ 14 июля 2020

Настройте планировщик задач так, чтобы он ждал, пока он завершит работу, и разрешите весенней загрузке выполнить graceful shutdown

@Bean
TaskSchedulerCustomizer taskSchedulerCustomizer() {
    return taskScheduler -> {
        taskScheduler.setAwaitTerminationSeconds(60);
        taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
    };
}

другое мнение

Используйте Shedlock для заблокировать планировщик на заданное время (время возможности обновления). Он также решает, что планировщик работает на всех / нескольких экземплярах вместо одного.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...