Java 如何暂停使用springboot启动的计划任务';s@Scheduled注解?

Java 如何暂停使用springboot启动的计划任务';s@Scheduled注解?,java,spring-boot,scheduled-tasks,Java,Spring Boot,Scheduled Tasks,我有一个简单的计划任务,它是使用@scheduled注释创建的。像这样的- public void doSomething() { // My code } 我还有一个蓝绿色的升级场景,其中此计划任务可能同时在蓝绿色集群中运行。如果此计划任务修改了数据库,则其中一个节点可能会覆盖来自另一个节点的数据-或最坏情况下的竞争条件 我想暂停绿色集群上的所有计划任务,直到它准备好接受流量。我已经将代码连接到侦听应用程序状态的更改 我探索了一些选择- 只需在任务开始时添加布尔值 向ThreadP

我有一个简单的计划任务,它是使用@scheduled注释创建的。像这样的-

public void doSomething() {
    // My code

}
我还有一个蓝绿色的升级场景,其中此计划任务可能同时在蓝绿色集群中运行。如果此计划任务修改了数据库,则其中一个节点可能会覆盖来自另一个节点的数据-或最坏情况下的竞争条件

我想暂停绿色集群上的所有计划任务,直到它准备好接受流量。我已经将代码连接到侦听应用程序状态的更改

我探索了一些选择-

  • 只需在任务开始时添加布尔值
  • 向ThreadPoolTaskScheduler添加装饰程序
  • 这些方法的问题在于,它们跳过特定计划的任务,而不是暂停它。因此,如果任务被跳过,比如在T,并且应用程序立即变为,应用程序将必须等待T+30分钟来刷新数据


    springboot中是否有方法暂停调度程序并立即恢复?

    自定义任务调度程序,使其等待作业完成,并允许spring boot正常关闭

    @Bean
    TaskSchedulerCustomizer taskSchedulerCustomizer() {
        return taskScheduler -> {
            taskScheduler.setAwaitTerminationSeconds(60);
            taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
        };
    }
    
    另一种观点


    用于在给定的时间量(可升级时间)内锁定计划程序。它还解决了在所有/多个实例(而不是一个实例)上运行的调度程序。

    看起来spring本机没有暂停计划任务的能力。在使用spring运行调度任务时,我倾向于使用Quartz调度器

    为了做到这一点,我们必须进行一些配置

    首先,我们必须设置上下文感知组件:

    @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调度在调度任务时提供了很大的灵活性


    这是一个不错的选择,但Shedlock中的锁定时间也是静态的。而且升级时间在多个环境中是可变的。如果我错了,请纠正我。