Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring 关闭TaskScheduler不会停止运行@Scheduled方法_Spring_Spring Boot_Taskscheduler_Spring Scheduled - Fatal编程技术网

Spring 关闭TaskScheduler不会停止运行@Scheduled方法

Spring 关闭TaskScheduler不会停止运行@Scheduled方法,spring,spring-boot,taskscheduler,spring-scheduled,Spring,Spring Boot,Taskscheduler,Spring Scheduled,我有一个类,其方法注释为@Scheduled @Component @Slf4j public class MyScheduler { @Scheduled(cron = "${polling-job-cron}") //each minute public void pollingJob() { log.info("starting polling job..."); //some work log.info("polling

我有一个类,其方法注释为@Scheduled

@Component
@Slf4j
public class MyScheduler {

    @Scheduled(cron = "${polling-job-cron}") //each minute
    public void pollingJob() {
        log.info("starting polling job...");
        //some work
        log.info("polling job finished.");
    }
}
以及taskScheduler的配置:

 @Bean
    public ThreadPoolTaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(5);
        scheduler.setThreadNamePrefix("mynameofscheduler");
        scheduler.setWaitForTasksToCompleteOnShutdown(true);
        scheduler.setAwaitTerminationSeconds(30);
        scheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        return scheduler;
    }
我试图通过使用等待
ContextClosedEvent
的类来使用优雅关机:

@Component
@Slf4j
public class GracefulShutdown implements ApplicationListener<ContextClosedEvent> {
    private final ApplicationContext context;
    private final ThreadPoolTaskScheduler taskScheduler;

    public GracefulShutdown(ApplicationContext context,
                            ThreadPoolTaskScheduler taskScheduler) {
        this.context = context;
        this.taskScheduler = taskScheduler;
    }

    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        log.info("Graceful shutdown - start");
        log.info("Closing task scheduler");
        taskScheduler.shutdown(); //1
        taskScheduler.getScheduledThreadPoolExecutor().shutdown(); //2
        log.error("Closed task scheduler");
        //give k8s a chance to hit in readinessProbe and stop sending requests to this pod
        try {
            Thread.sleep(80000); //3
        } catch (InterruptedException error) {
            log.info("error while trying to sleep");
            error.printStackTrace();
        }
        log.info("Closing spring context with startup date, {}, parent: {}, id: {}, name: {}",
            context.getStartupDate(), context.getParent(), context.getId(), context.getDisplayName());
        ((ConfigurableApplicationContext) context).close();
        log.info("Graceful shutdown - end");
    }
threadPoolPrefix记录在这些行的前面(由于行太长,无法读取,所以我在上面删掉了该行):

我想可能使用了其他taskScheduler,我关闭了一个错误的taskScheduler,但它都是在
@Bean
thx中配置的
mynameofscheduler
。我搞砸了,弹簧关闭了水流。我已通过注册关机挂钩修复了此问题:

 public static void main(String[] args) {
    ConfigurableApplicationContext context = SpringApplication.run(AgileStreamApplication.class, args);
    Runtime.getRuntime().addShutdownHook(new Thread(new GracefulShutdownHook(context)));
}

现在我不必显式地关闭TaskScheduler。它由spring完成。

因为默认情况下,ScheduledThreadPoolExecutor将等待所有延迟的计划任务完成执行,即使计划任务当时没有运行

请尝试以下操作:

@Bean
public ThreadPoolTaskScheduler taskScheduler() {
    ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler() {
        private static final long serialVersionUID = -1L;
        @Override
        public void destroy() {
            this.getScheduledThreadPoolExecutor().setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
            super.destroy();
        }
    };
    scheduler.setPoolSize(5);
    scheduler.setThreadNamePrefix("mynameofscheduler");
    scheduler.setWaitForTasksToCompleteOnShutdown(true);
    scheduler.setAwaitTerminationSeconds(30);
    scheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
    return scheduler;
}

然后ScheduledThreadPoolExecutor将只等待当前正在运行的计划任务完成执行。

Spring已经调用了
shutdown
方法,因此无需再次执行。您的代码还将导致一个错误,因为上下文已经关闭,并且您正在再次调用close。将抛出已关闭异常(或类似异常)的AIK。所以我想说,您尝试正常关机实际上是在阻止正常关机。不幸的是,我还没有开始无缘无故地关闭taskScheduler。我注意到它仍然在Thread.sleep(80000)时运行@Scheduled方法(这对于kubernetes来说是个肮脏的把戏)。因此,否-它没有关闭它,至少没有以我期望的方式关闭:)+我没有收到您提到的错误。它关闭是因为
ThreadPoolTaskScheduler
实现了
DisposableBean
,并且在关闭/销毁上下文时调用了
Distroy
方法。因此,是的,它是关闭的,但关闭不会阻止它接受其他任务(这是您在日志中看到的),再次关闭它(一次又一次)不会改变这一点。另外,您确定这是您的
@Scheduled
使用的
任务调度程序吗?是的,此任务调度程序作为其threadNamePrefix记录在与“starting polling job.”相同的行上(我已经将其删除,因为行很长,但将编辑/添加到问题中),然后它还没有关闭,这很奇怪(显然你的“修复”也没有帮助)。是否(出于某种原因)有多个实例?你能创建一个复制实例吗?
 public static void main(String[] args) {
    ConfigurableApplicationContext context = SpringApplication.run(AgileStreamApplication.class, args);
    Runtime.getRuntime().addShutdownHook(new Thread(new GracefulShutdownHook(context)));
}
@Bean
public ThreadPoolTaskScheduler taskScheduler() {
    ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler() {
        private static final long serialVersionUID = -1L;
        @Override
        public void destroy() {
            this.getScheduledThreadPoolExecutor().setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
            super.destroy();
        }
    };
    scheduler.setPoolSize(5);
    scheduler.setThreadNamePrefix("mynameofscheduler");
    scheduler.setWaitForTasksToCompleteOnShutdown(true);
    scheduler.setAwaitTerminationSeconds(30);
    scheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
    return scheduler;
}