Java 如何优雅地结束spring@Schedule任务?
我正在尝试让spring引导服务优雅地结束。它有一个带有Java 如何优雅地结束spring@Schedule任务?,java,spring,spring-boot,rabbitmq,spring-scheduled,Java,Spring,Spring Boot,Rabbitmq,Spring Scheduled,我正在尝试让spring引导服务优雅地结束。它有一个带有@Scheduled注释的方法。该服务将spring数据用于DB,将spring云流用于RabbitMQ。在计划的方法结束之前,DB和RabbitMQ是可访问的,这一点至关重要。有一个autoscaler,它经常启动/停止服务实例,停止时崩溃不是一个选项 从这篇文章中,我认为这应该足以补充 @Bean TaskSchedulerCustomizer taskSchedulerCustomizer() { re
@Scheduled
注释的方法。该服务将spring数据用于DB,将spring云流用于RabbitMQ。在计划的方法结束之前,DB和RabbitMQ是可访问的,这一点至关重要。有一个autoscaler,它经常启动/停止服务实例,停止时崩溃不是一个选项
从这篇文章中,我认为这应该足以补充
@Bean
TaskSchedulerCustomizer taskSchedulerCustomizer() {
return taskScheduler -> {
taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
taskScheduler.setAwaitTerminationSeconds(30);
};
}
spring应该等待关闭应用程序,直到计划的方法完成或30秒过期
当服务在执行调度方法时停止时,我可以从日志中看到以下内容
@SpringBootApplication(scanBasePackages = {
"xx.yyy.infop.dao",
"xx.yyy.infop.compress"})
@EntityScan("ch.sbb.infop.common.entity")
@EnableJpaRepositories({"xx.yyy.infop.dao", "xx.yyy.infop.compress.repository"})
@EnableBinding(CompressSink.class)
@EnableScheduling
public class ApplicationCompress {
@Value("${max.commpress.timout.seconds:300}")
private int maxCompressTimeoutSeconds;
public static void main(String[] args) {
SpringApplication.run(ApplicationCompress.class, args);
}
@Bean
TaskSchedulerCustomizer taskSchedulerCustomizer() {
return taskScheduler -> {
taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
taskScheduler.setAwaitTerminationSeconds(maxCompressTimeoutSeconds);
};
}
}
这就是豆子:
@Component
@Profile("!integration-test")
public class CommandReader {
private static final Logger LOGGER = LoggerFactory.getLogger(CommandReader.class);
private final CompressSink compressSink;
private final CommandExecutor commandExecutor;
CommandReader(CompressSink compressSink, CommandExecutor commandExecutor) {
this.compressSink = compressSink;
this.commandExecutor = commandExecutor;
}
@PreDestroy
private void preDestory() {
LOGGER.info("preDestory");
}
@Scheduled(fixedDelay = 1000)
public void poll() {
LOGGER.debug("Start polling.");
ParameterizedTypeReference<CompressCommand> parameterizedTypeReference = new ParameterizedTypeReference<>() {
};
if (!compressSink.inputSync().poll(this::execute, parameterizedTypeReference)) {
compressSink.inputAsync().poll(this::execute, parameterizedTypeReference);
}
LOGGER.debug("Finished polling.");
}
private void execute(Message<?> message) {
CompressCommand compressCommand = (CompressCommand) message.getPayload();
// uses spring-data to write to DB
CompressResponse compressResponse = commandExecutor.execute(compressCommand);
// Schreibt die Anwort in Rensponse-Queue
compressSink.outputResponse().send(MessageBuilder.withPayload(compressResponse).build());
}
}
我已经测试了这个配置,它应该与您的
任务调度程序的配置相同:
spring.task.scheduling.shutdown.await-termination=true
spring.task.scheduling.shutdown.await-termination-period=30s
Spring在所有服务可用的情况下等待30秒,然后关闭任何活动任务。如果没有活动任务,则立即关闭
值得一提的是,让我想到这个问题的是以非常类似的方式配置的@Async
方法的优雅关闭:
spring.task.execution.shutdown.await-termination=true
spring.task.execution.shutdown.await-termination-period=1s
或在代码中:
@Bean
public TaskExecutorCustomizer taskExecutorCustomizer() {
// Applies to @Async tasks, not @Scheduled as in the question
return (customizer) -> {
customizer.setWaitForTasksToCompleteOnShutdown(true);
customizer.setAwaitTerminationSeconds(10);
};
}
回到您的案例中,我猜想任务调度程序rcustomizer
没有实际执行,或者在执行后被其他内容覆盖
对于第一个选项,通过添加日志语句或在taskSchedulerCustomizer()
中设置断点进行验证
对于第二个选项,我建议在TaskSchedulerBuilder::configure()
中设置一个断点以查看发生了什么。一旦调试器中断了该方法,请在taskScheduler
的ExecutorConfigurationSupport::awaitTerminationMillis
属性上添加一个数据断点,以查看该属性是否在其他地方被修改
您可以在方法ExecutorConfigurationSupport::WaitiveTerminationIfEssential
中看到关机过程中使用的最终终止期。如果不需要,则无法强制执行此操作。任何事情都可能发生。比如说,如果停电怎么办?是的,当然。我说的是正常关机,spring的关机钩子应该确保以友好的方式关机。如果你使用AWS的autoscaler,它会在缩小应用程序和关闭JVM之前向你的虚拟机发送SIGKILL。也许在程序中添加一个?
@Bean
public TaskExecutorCustomizer taskExecutorCustomizer() {
// Applies to @Async tasks, not @Scheduled as in the question
return (customizer) -> {
customizer.setWaitForTasksToCompleteOnShutdown(true);
customizer.setAwaitTerminationSeconds(10);
};
}