开启优雅关闭终端:endpoints.shutdown.enabled: true
调用接口: POST /shutdown
-
docker stop/restart [-t seconds] [container_id] 发送中断信号,不会接收新的请求,之前的请求会继续运行
-
新请求无法创建连接:因为服务不再接收新的请求,所以会报503:Service Unavailable, 建议Client设置一个合适的 连接超时时间
-
超时时间[-t]:到达超时时间后,服务仍会立即中断,所以最好 设置一个合适的超时时间
-
日志:接收到中断信号后,log不会再打印,但
log.isXXXEnabled()
仍返回true
! 所以不要用log作为判断请求中断的标记,而是用System.out.print
-
该方法只是手动关闭服务线程,前几种方法已经可以做到,不建议使用
-
实现 自定义 GracefulShutdownConfiguration 通过
@ImportAutoConfiguration(GracefulShutdownConfiguration.class)
启用配置 -
问题:停止后服务仍未关闭,用
jstack
看到仍然有线程在执行(基于我当前的服务):-
org.springframework.cloud.consul.config.ConfigWatch 解决:
spring.cloud.consul.config.watch.enabled: false
但是有些服务是需要开启的 查看源码,该线程默认要等待55s来判断结束状态,时间较长 -
ch.qos.logback.classic.AsyncAppender 解决:logback-spring 里加上
<shutdownHook class="ch.qos.logback.core.hook.DelayingShutdownHook"/>``ShutdownHookBase#close
里会调用Context.stop()
进行关闭
-
@Slf4j
public class GracefulShutdownConfiguration {
@Bean
public GracefulShutdown gracefulShutdown() {
return new GracefulShutdown();
}
@Bean
public TomcatEmbeddedServletContainerFactory webServerFactory(final GracefulShutdown gracefulShutdown) {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
factory.addConnectorCustomizers(gracefulShutdown);
return factory;
}
class GracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {
private volatile Connector connector;
@Override
public void customize(Connector connector) {
this.connector = connector;
}
@Override
public void onApplicationEvent(ContextClosedEvent event) {
log.info("signal: shutdown");
log.info(event.toString());
this.connector.pause();
Executor executor = this.connector.getProtocolHandler().getExecutor();
if (executor instanceof ThreadPoolExecutor) {
try {
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
threadPoolExecutor.shutdown();
log.info(threadPoolExecutor.getActiveCount() + "");
if (!threadPoolExecutor.awaitTermination(30, TimeUnit.SECONDS)) {
log.warn("Tomcat thread pool did not shut down gracefully within "
+ "30 seconds. Proceeding with forceful shutdown");
}
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}
}
-
spring boot issue: Shut down embedded servlet container gracefully
-
A graceful shutdown starter for Spring-Boot: spring-boot-graceful-shutdown
-
graceful shutdown by impl
TomcatConnectorCustomizer
: Graceful Shutdown Spring Boot Applications