programing

스프링 부트 정상 종료

skycolor 2023. 8. 30. 21:32
반응형

스프링 부트 정상 종료

내장된 Tomcat에서 지원하는 Spring Boot 애플리케이션을 개발 중이며 다음 단계로 정상 종료를 개발해야 합니다.

  1. 새 HTTP 요청 처리 중지(웹 컨테이너 중지)
  2. 이미 수락된 모든 요청 처리
  3. Spring 응용 프로그램 종료 컨텍스트

*위 단계를 순차적으로 수행(하나씩)

어떻게 하면 이를 달성할 수 있을까요?

추신: 스프링 부트 1.5.20.릴리스, Java 8

정상 종료 지원은 Spring Boot 2.3(2020년 5월 출시)에 추가되었습니다.이렇게 하면 컨텍스트를 닫고 컨테이너를 종료하기 전에 활성 요청을 완료할 수 있습니다.

정상 종료를 사용하도록 설정하면 종료 시 응용 프로그램이 다음 단계를 순차적으로 수행합니다.

  • 새 요청 수락 중지
  • 이미 수락된 요청을 처리하기 위해 구성 가능한 시간을 기다립니다.
  • 정지 용기
  • 내장된 서버 중지

릴리스 정보에서:

정상 종료는 4개의 내장 웹 서버(Jetty, Reactor Netty, Tomcat 및 언더도우)와 반응형 및 서블릿 기반 웹 애플리케이션 모두에서 지원됩니다.사용하여 활성화할 경우server.shutdown=graceful종료 시 웹 서버는 더 이상 새 요청을 허용하지 않으며 활성 요청이 완료될 때까지 유예 기간을 기다립니다.유예 기간은 다음을 사용하여 구성할 수 있습니다.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 호에서 설명한 바와 같이 서버의 커넥터를 수정하여 새로운 요청 수락을 중지합니다.

저는 다음과 같은 결과를 얻었습니다.

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;
  }
...

심플한 스프링 부츠 자체가 기능을 제공합니다.https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/ #boot-message-application-message

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

출력에서 모든 현재 스레드가 닫혀 있는 것을 볼 수 있습니다.출력:

소리쳐 +++===

2020-06-09 11:21:45,543
DEBUG[main][c.u.j.c.EnableEncryptablePropertiesBeanFactoryPostProcessor]
Application Event Raised: ExitCodeEvent  2020-06-09 11:21:45,543
DEBUG[main][c.u.j.c.EnableEncryptablePropertiesBeanFactoryPostProcessor]
Application Event Raised: ExitCodeEvent  2020-06-09 11:21:45,546
DEBUG[main][c.u.j.c.EnableEncryptablePropertiesBeanFactoryPostProcessor]
Application Event Raised: ContextClosedEvent  2020-06-09 11:21:45,546
DEBUG[main][c.u.j.c.EnableEncryptablePropertiesBeanFactoryPostProcessor]
Application Event Raised: ContextClosedEvent  2020-06-09 11:21:45,547
INFO [main][o.a.kafka.clients.producer.KafkaProducer] [Producer
clientId=producer-1] Closing the Kafka producer with timeoutMillis =
30000 ms.  2020-06-09 11:21:45,548
DEBUG[kafka-producer-network-thread |
producer-1][o.a.k.clients.producer.internals.Sender] [Producer
clientId=producer-1] Beginning shutdown of Kafka producer I/O thread,
sending remaining records.  2020-06-09 11:21:45,551
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name connections-closed:  2020-06-09 11:21:45,554
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name connections-created:  2020-06-09 11:21:45,554
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name successful-authentication:  2020-06-09 11:21:45,558
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name failed-authentication:  2020-06-09 11:21:45,558
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name bytes-sent-received:  2020-06-09 11:21:45,559
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name bytes-sent:  2020-06-09 11:21:45,559
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name bytes-received:  2020-06-09 11:21:45,560
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name select-time:  2020-06-09 11:21:45,561
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name io-time:  2020-06-09 11:21:45,570
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name node--1.bytes-sent  2020-06-09 11:21:45,570
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name node--1.bytes-received  2020-06-09 11:21:45,570
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name node--1.latency  2020-06-09 11:21:45,571
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name node-0.bytes-sent  2020-06-09 11:21:45,571
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name node-0.bytes-received  2020-06-09 11:21:45,573
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name node-0.latency  2020-06-09 11:21:45,573
DEBUG[kafka-producer-network-thread |
producer-1][o.a.k.clients.producer.internals.Sender] [Producer
clientId=producer-1] Shutdown of Kafka producer I/O thread has
completed.  2020-06-09 11:21:45,607
DEBUG[main][o.a.kafka.clients.producer.KafkaProducer] [Producer
clientId=producer-1] Kafka producer has been closed  2020-06-09
11:21:45,611 DEBUG[main][o.hibernate.internal.SessionFactoryImpl]
HHH000031: Closing  2020-06-09 11:21:45,611
DEBUG[main][o.h.type.spi.TypeConfiguration$Scope] Un-scoping
TypeConfiguration
[org.hibernate.type.spi.TypeConfiguration$Scope@5dfd31f4] from
SessionFactory [org.hibernate.internal.SessionFactoryImpl@62a54948] 
2020-06-09 11:21:45,612
DEBUG[main][o.h.s.i.AbstractServiceRegistryImpl] Implicitly
destroying ServiceRegistry on de-registration of all child
ServiceRegistries  2020-06-09 11:21:45,613
DEBUG[main][o.h.b.r.i.BootstrapServiceRegistryImpl] Implicitly
destroying Boot-strap registry on de-registration of all child
ServiceRegistries  2020-06-09 11:21:45,613 INFO
[main][com.zaxxer.hikari.HikariDataSource] HikariPool-1 - Shutdown
initiated...  2020-06-09 11:21:45,754 INFO
[main][com.zaxxer.hikari.HikariDataSource] HikariPool-1 - Shutdown
completed.

언급URL : https://stackoverflow.com/questions/56040542/spring-boot-graceful-shutdown

반응형