У меня есть класс с методом, помеченным @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");
}
и даже несмотря на то, что я закрываю taskScheduler и базовый taskExecutor, новые задачи по-прежнему выполняются @Scheduled. Код GracefulShutdown
запускается при отправке SIGTERM, а кроме закрытия taskScheduler он работает нормально.
Graceful shutdown - start
Closing task scheduler
Closed task scheduler
starting polling job...
polling job finished
starting polling job...
polling job finished.
threadPoolPrefix регистрируется перед этими строками (я вырезал это выше, так как строка была слишком длинной для чтения):
{"timeMillis":1534234560001,"thread":"mynameofscheduler","level":"INFO","loggerName":"myclassr","message":"starting polling job..."
Я подумал, что, возможно, используется какой-то другой taskScheduler, и я закрываю не тот, но все это mynameofscheduler
, которое настроено в @Bean
shutdown
, поэтому повторять это не нужно. Ваш код также приведет к ошибке, поскольку контекст уже закрыт, и вы снова вызываете close. AFAIK, который вызовет уже закрытое исключение (или что-то подобное). Поэтому я бы сказал, что ваша попытка корректного выключения на самом деле препятствует корректному завершению работы. - person M. Deinum   schedule 14.08.2018ThreadPoolTaskScheduler
реализуетDisposableBean
, а методdestroy
вызывается, когда контекст закрывается / уничтожается. Так что да, это выключение, но выключение не мешает ему принимать другие задачи (это то, что вы видите в своем журнале), повторное выключение (и снова) не изменит этого. Также вы уверены, что этоTaskScheduler
, который используется вашим@Scheduled
? - person M. Deinum   schedule 14.08.2018ContextClosedEvent
запускается до того, как фактические beans будут остановлены, поэтому, если вы спите внутри этогоApplicationListener
, это фактически предотвращает остановкуApplicationContext
и, таким образом, выключениеTaskScheduler
. ВыключениеTaskScheduler
вручную фактически прекращает планирование событий в моем небольшом тесте. - person M. Deinum   schedule 14.08.2018sleep
вShutdownEndpoint
не останавливает правильное закрытие контекста, потому что это еще не началось. Ваш блокирует дальнейшую обработкуdoClose
вAbstractApplicationContext
, предотвращая завершение работы beans. - person M. Deinum   schedule 14.08.2018