Mechanizm Graceful Shutdown w Spring Boot


Mechanizm Graceful Shutdown w Spring Boot

Bezpieczne zamknięcie aplikacji Graceful Shutdown to mechanizm który pozwala zamknąć aplikację wyłączając uprzednie wszystkie inne procesy w pewnym ustalonym czasie. Jeśli czas ten zostanie przekroczony to jest to sytuacja wyjątkowa którą należy prawidłowo obsłużyć. Zaczynamy! Tworzymy nowy projekt Spring Boota a następnie:

Pierwszy komponent – założony czas na zamknięcie procesów to 20 sekund:

@Component
public class GracefulShutdown implements ApplicationListener<ContextClosedEvent> {

    private final TomcatGracefulShutdownConnector gracefulShutdown;

    public GracefulShutdown(final TomcatGracefulShutdownConnector gracefulShutdown) {
        this.gracefulShutdown = gracefulShutdown;
    }

    @Override
    public void onApplicationEvent(final ContextClosedEvent contextClosedEvent) {
        try {
            final ThreadPoolExecutor threadPoolExecutor = gracefulShutdown.threadPoolExecutor().orElseThrow(() -> new IllegalStateException());
            threadPoolExecutor.shutdown();
            if(!threadPoolExecutor.awaitTermination(20, TimeUnit.SECONDS)) {
                System.out.println("time out...");
            } else {
                System.out.println("graceful activated");
            }
        } catch(InterruptedException ex) {
            Thread.currentThread().interrupt();
        }
    }
}

Drugi komponent:

public class TomcatGracefulShutdownConnector implements TomcatConnectorCustomizer {

    private volatile Connector connector;

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

    public Optional<ThreadPoolExecutor> threadPoolExecutor() {
        this.connector.pause();
        Executor executor = this.connector.getProtocolHandler().getExecutor();
        if(executor instanceof ThreadPoolExecutor) {
            return Optional.of((ThreadPoolExecutor) executor);
        }
        return Optional.empty();
    }
}

RestController:

@RestController
public class RestControllerProcess {

    @GetMapping("/process-1")
    String longJob() throws InterruptedException {
        Thread.sleep(15_000);
        return "Done";
    }
    @GetMapping("/process-2")
    String veryLongJob() throws InterruptedException {
        Thread.sleep(25_000);
        return "Done";
    }
}

Klasa startowa:

@SpringBootApplication
public class GracefulShutdownApplication {

	public static void main(String[] args) {
		SpringApplication.run(GracefulShutdownApplication.class, args);
	}

	@Bean
	public TomcatGracefulShutdownConnector tomcatGracefulShutdownConnector() {
		return new TomcatGracefulShutdownConnector();
	}

	@Bean
	public ConfigurableServletWebServerFactory webServerFactory(final TomcatGracefulShutdownConnector tomcatGracefulShutdownConnector) {
		TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
		factory.addConnectorCustomizers(tomcatGracefulShutdownConnector);
		return factory;
	}
}

Testy:

Uruchamiamy:

http://localhost:8080/process-1

i z poziomu IntelliJ wysyłamy sygnał sigterm:

Wynik:

graceful activated

Uruchamiany:

http://localhost:8080/process-2

i z poziomu IntelliJ wysyłamy sygnał sigterm:

Wynik:

time out...


Leave a comment

Your email address will not be published.


*