繁体   English   中英

Spring Boot 优雅关机

[英]Spring Boot graceful shutdown

我正在开发一个由嵌入式 Tomcat 支持的 Spring Boot 应用程序,我需要通过以下步骤开发一个优雅的关闭:

  1. 停止处理新的 HTTP 请求(停止 Web 容器)
  2. 处理所有已接受的请求
  3. 关闭 Spring ApplicationContext

*依次(一一)执行以上步骤

我怎样才能做到这一点?

PS Spring Boot 1.5.20.RELEASE,Java 8

我已经结束了:

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.catalina.connector.Connector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;

public class GracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {

  private static final Logger log = LoggerFactory.getLogger(GracefulShutdown.class);
  private volatile Connector connector;

  @Override
  public void customize(Connector connector) {
    this.connector = connector;
  }

  @Override
  public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
    log.info("Protocol handler is shutting down");

    this.connector.pause();
    Executor executor = this.connector.getProtocolHandler().getExecutor();
    if (executor instanceof ThreadPoolExecutor) {
      try {
        ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
        threadPoolExecutor.shutdown();

        if (!threadPoolExecutor.awaitTermination(30, TimeUnit.SECONDS))
          log.warn("Tomcat thread pool did not shut down gracefully within 30 seconds. Proceeding with forceful shutdown");
        else
          log.info("Protocol handler shut down");

      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
      }
    }
  }
}

一些额外的豆类:

import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
...
  @Bean
  public GracefulShutdown gracefulShutdown() {
    return new GracefulShutdown();
  }

  @Bean
  public EmbeddedServletContainerFactory servletContainer(final GracefulShutdown gracefulShutdown) {
    TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
    factory.addConnectorCustomizers(gracefulShutdown);
    return factory;
  }
...

Spring Boot 2.3(2020 年 5 月发布)中添加了优雅关闭支持。 这允许在关闭上下文和关闭容器之前完成活动请求。

启用优雅关机后,应用程序将在关机时依次执行以下步骤:

  • 停止接受新请求
  • 将等待一些可配置的时间来处理已接受的请求
  • 停止容器
  • 停止嵌入式服务器

发行说明

所有四个嵌入式 Web 服务器(Jetty、Reactor Netty、Tomcat 和 Undertow)以及反应式和基于 Servlet 的 Web 应用程序都支持正常关闭。 当使用server.shutdown=graceful启用时,关闭时,Web 服务器将不再允许新请求,并将等待活动请求完成的宽限期。 可以使用spring.lifecycle.timeout-per-shutdown-phase配置宽限期。


  • 要启用正常关闭,请将server.shutdown=graceful添加到属性(默认情况下设置为immediate )。
  • 可以使用spring.lifecycle.timeout-per-shutdown-phase属性配置宽限期(例如: spring.lifecycle.timeout-per-shutdown-phase=1m

对于 Spring Boot < 2.3,您需要修改服务器的连接器以停止接受新请求,如Spring GitHub 问题中所述

关于 Matthew I. 的回答。 请注意,他使用的是 JDK 'ThreadPoolExecutor',而他应该使用 Tomcat ThreadPoolExecutor。 ==>'org.apache.tomcat.util.threads.ThreadPoolExecutor;

否则关闭钩子不会真正等待 Tomcat 线程停止。

它的简单,Spring boot 本身提供了功能。 https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-application-exit

void shoutdown(){
       System.out.println("====+= Shoutdown +++===");
       System.exit(SpringApplication.exit(apc, this.exitCodeGenerator()));

   }

您可以在输出中看到,所有当前线程都已关闭。 输出:

====+= 大喊大叫 +++===

  • 2020-06-09 11:21:45,543 DEBUG[main][cujcEnableEncryptablePropertiesBeanFactoryPostProcessor] 引发的应用程序事件:ExitCodeEvent 2020-06-09 11:21:45,543 DEBUG[main][cujcEnableFactoryEncryptablePropertiesBeanFactoryPostProcessor]ApplicationEvent :21:45,546 DEBUG[main][cujcEnableEncryptablePropertiesBeanFactoryPostProcessor] 应用程序事件引发:ContextClosedEvent 2020-06-09 11:21:45,546 DEBUG[main][cujcEnableEncryptablePropertiesBeanFactoryPostProcessor] Application Event Raised: ContextClosedEvent 202052041204204104041 main][oakafka.clients.producer.KafkaProducer] [Producer clientId=producer-1] 使用 timeoutMillis = 30000 ms 关闭 Kafka 生产者。 2020-06-09 11:21:45,548 调试[kafka-producer-network-thread | producer-1][oakclients.producer.internals.Sender] [Producer clientId=producer-1] Kafka 生产者 I/O 线程开始关闭,发送剩余记录。 2020-06-09 11:21:45,551 调试[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] 删除了名称为连接关闭的传感器:2020-06-09 11:21:45,554 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] 删除了名称为 connection-created 的传感器:2020-06-09 11:21:45,554 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] 删除了名称为 success-authentication 的传感器:2020-06-09 11:21:45,558 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] 删除了名称为 failed-authentication 的传感器:2020-06-09 11:21:45,558 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] 删除了名称为 bytes-sent-received 的传感器:2020-06-09 11:21:45,559 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] 删除了名称为 bytes-sent 的传感器:2020-06-09 11:21:45,559 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] 删除了名称为 bytes-received 的传感器:2020-06-09 11:21:45,560 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] 删除了名称为 select-time 的传感器:2020-06-09 11:21:45,561 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] 删除了名称为 io-time 的传感器:2020-06-09 11:21:45,570 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] 删除了名称为 node--1.bytes-sent 的传感器 2020-06-09 11:21:45,570 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] 删除了名称为 node--1.bytes-received 的传感器 2020-06-09 11:21:45,570 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] 删除了名称为 node--1.latency 的传感器 2020-06-09 11:21:45,571 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] 删除了名称为 node-0.bytes-sent 的传感器 2020-06-09 11:21:45,571 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] 删除了名称为 node-0.bytes-received 的传感器 2020-06-09 11:21:45,573 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] 删除了名称为 node-0.latency 的传感器 2020-06-09 11:21:45,573 DEBUG[kafka-producer-network-thread | producer-1][oakclients.producer.internals.Sender] [Producer clientId=producer-1] Kafka生产者I/O线程关闭完成。 2020-06-09 11:21:45,607 DEBUG[main][oakafka.clients.producer.KafkaProducer] [Producer clientId=producer-1] Kafka producer 已关闭 2020-06-09 11:21:45,611 DEBUG[main] [o.hibernate.internal.SessionFactoryImpl] HHH000031:关闭 2020-06-09 11:21:45,611 DEBUG[main][ohtype.spi.TypeConfiguration$Scope] Un-scopeing TypeConfiguration [org.hibernate.type.spi.TypeConfiguration$ Scope@5dfd31f4] 来自 SessionFactory [org.hibernate.internal.SessionFactoryImpl@62a54948] 2020-06-09 11:21:45,612 DEBUG[main][ohsiAbstractServiceRegistryImpl] 隐式销毁 ServiceRegistry 上的所有子 ServiceRegistry-ServiceRegistry-020200202020 11:21:45,613 DEBUG[main][ohbriBootstrapServiceRegistryImpl] 在注销所有子 ServiceRegistries 时隐式销毁 Boot-strap 注册表 2020-06-09 11:21:45,613 INFO [main][com.zaxxer.hikariPDataSource] Hikari.Hkari -1 - 关闭启动... 2020-06-09 11:21:45,754 INFO [main][com.zaxxer.hikari.HikariDataSource] HikariPool-1 - 关闭完成 .

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM