Spring Boot 从 @Scheduled 方法中优雅地停止

huangapple go评论56阅读模式
英文:

Spring Boot Stop Gracefuly From @Scheduled Method

问题

以下是翻译好的代码部分:

我正在尝试根据数据库的值停止一个基于Spring Boot的应用程序就像这样

@Scheduled(fixedDelay = 3000)
public void checkShutdown() {

    boolean shouldShutdown = readFromDatabase();

    if (shouldShutdown) {
        log.info("Shutdown requested.");
        SpringApplication.exit(applicationContext, () -> 0);
        return;
    }
}

关于异常部分,这里是异常信息的翻译:

2023-05-13T10:24:47.924-03:00  INFO 248948 --- [   scheduling-1] c.e.d.example.service.ShutdownService   : Shutdown requested.
2023-05-13T10:24:47.934-03:00  WARN 248948 --- [   scheduling-1] o.s.s.c.ThreadPoolTaskScheduler          : Interrupted while waiting for executor 'taskScheduler' to terminate
2023-05-13T10:24:47.939-03:00  INFO 248948 --- [   scheduling-1] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2023-05-13T10:24:47.944-03:00  INFO 248948 --- [   scheduling-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2023-05-13T10:24:47.949-03:00  WARN 248948 --- [   scheduling-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Interrupted during closing

java.lang.InterruptedException: null
	at java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:1660) ~[na:na]
	...

还有关于尝试的属性设置部分,这里是它们的翻译:

我也尝试了设置以下属性,但没有任何改变:

spring:
  task:
    execution:
      shutdown:
        await-termination: true
        await-termination-period: 15s
    scheduling:
      shutdown:
        await-termination: true
        await-termination-period: 15s

另外,我还尝试了调用applicationContext.close()而不是SpringApplication.exit,但也没有任何改变。

英文:

I am trying to stop a Spring Boot application based on a database value like this:

@Scheduled(fixedDelay = 3000)
public void checkShutdown() {

	boolean shouldShutdown = readFromDatabase();

	if (shouldShutdown) {
		log.info("Shutdown requested.");
		SpringApplication.exit(applicationContext, () -> 0);
		return;
	}
}

When the app is exiting, it throws a nasty exception, because the Hikari data source is interrupted and not allowed to close gracefully. Here is the exception:

2023-05-13T10:24:47.924-03:00  INFO 248948 --- [   scheduling-1] c.e.d.example.service.ShutdownService   : Shutdown requested.
2023-05-13T10:24:47.934-03:00  WARN 248948 --- [   scheduling-1] o.s.s.c.ThreadPoolTaskScheduler          : Interrupted while waiting for executor 'taskScheduler' to terminate
2023-05-13T10:24:47.939-03:00  INFO 248948 --- [   scheduling-1] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2023-05-13T10:24:47.944-03:00  INFO 248948 --- [   scheduling-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2023-05-13T10:24:47.949-03:00  WARN 248948 --- [   scheduling-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Interrupted during closing

java.lang.InterruptedException: null
	at java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:1660) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor.awaitTermination(ThreadPoolExecutor.java:1464) ~[na:na]
	at com.zaxxer.hikari.pool.HikariPool.shutdown(HikariPool.java:243) ~[HikariCP-5.0.1.jar:na]
	at com.zaxxer.hikari.HikariDataSource.close(HikariDataSource.java:351) ~[HikariCP-5.0.1.jar:na]
	at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:222) ~[spring-beans-6.0.8.jar:6.0.8]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:587) ~[spring-beans-6.0.8.jar:6.0.8]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:559) ~[spring-beans-6.0.8.jar:6.0.8]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:1189) ~[spring-beans-6.0.8.jar:6.0.8]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:520) ~[spring-beans-6.0.8.jar:6.0.8]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:1182) ~[spring-beans-6.0.8.jar:6.0.8]
	at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1084) ~[spring-context-6.0.8.jar:6.0.8]
	at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1053) ~[spring-context-6.0.8.jar:6.0.8]
	at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:1003) ~[spring-context-6.0.8.jar:6.0.8]
	at org.springframework.boot.SpringApplication.close(SpringApplication.java:1397) ~[spring-boot-3.0.6.jar:3.0.6]
	at org.springframework.boot.SpringApplication.exit(SpringApplication.java:1350) ~[spring-boot-3.0.6.jar:3.0.6]
	at com.example.service.ShutdownService.checkShutdown(ShutdownService.java:34) ~[classes/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
	at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) ~[spring-context-6.0.8.jar:6.0.8]
	at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-6.0.8.jar:6.0.8]
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) ~[na:na]
	at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305) ~[na:na]
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
	at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]

I have tried setting the following properties, but it made no difference:

spring:
  task:
    execution:
      shutdown:
        await-termination: true
        await-termination-period: 15s
    scheduling:
      shutdown:
        await-termination: true
        await-termination-period: 15s

I also tried calling applicationContext.close() instead of SpringApplication.exit, but it also made no difference.

答案1

得分: 1

@Scheduled(fixedDelay = 3000)
public void checkShutdown() {

    boolean shouldShutdown = readFromDatabase();

    if (shouldShutdown) {
        log.info("Shutdown requested.");
        hikariDataSource.close();
        SpringApplication.exit(applicationContext, () -> 0);
        return;
    }
}
英文:

Calling HikariDataSource.close() has done the trick:

@Scheduled(fixedDelay = 3000)
public void checkShutdown() {

    boolean shouldShutdown = readFromDatabase();

    if (shouldShutdown) {
        log.info("Shutdown requested.");
        hikariDataSource.close();
        SpringApplication.exit(applicationContext, () -> 0);
        return;
    }
}

答案2

得分: 0

可以根据您的需求在服务/组件bean上执行类似以下操作:

@PreDestroy
public void close() {
// 应用程序已关闭
}


<details>
<summary>英文:</summary>

Can do like this on a Service/Component bean, depending on your requirements:

@PreDestroy
public void close() {
// application is closed
}


</details>



huangapple
  • 本文由 发表于 2023年5月13日 21:40:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/76243024.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定