Je développe une application Spring Boot soutenue par Tomcat intégré et je dois développer un arrêt en douceur avec les étapes suivantes:
* faites les étapes ci-dessus séquentiellement (une par une)
Comment puis-je atteindre cet objectif?
PS Spring Boot 1.5.20.RELEASE, Java 8
4 Réponses :
J'ai fini avec:
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; } ...
quelques haricots supplémentaires:
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(); } } } }
Blog avec une solution «similaire»: blog.marcosbarbero.com/graceful-shutdown-spring-boot-apps Et voici le lien vers le problème de démarrage de printemps pour un arrêt en douceur du conteneur de servlets: github.com/spring-projects/spring- démarrage / issues / 4657
En regardant cette solution, je crois comprendre qu'elle va forcer une attente de 30 secondes après la demande d'arrêt et seulement après 30 secondes, effectuer un arrêt progressif. Mais le PO veut aussi arrêter les demandes. Comment cela peut-il être réalisé par votre solution?
Concernant la réponse de Matthew I. Veuillez noter qu'il utilise JDK 'ThreadPoolExecutor' alors qu'il devrait utiliser Tomcat ThreadPoolExecutor. ==> 'org.apache.tomcat.util.threads.ThreadPoolExecutor;
Sinon, le hook d'arrêt n'attendra pas vraiment l'arrêt des threads Tomcat.
Bonjour Johnny, vous devriez créer un commentaire sur la réponse au lieu d'en créer un nouveau :)
Son démarrage Simple, Spring lui-même fournit des fonctionnalités. 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())); }
Vous pouvez voir en sortie, tous les threads actuels étant fermés. Production:
==== + = Shoutdown +++ ===
La prise en charge de l'arrêt progressif a été ajoutée dans Spring Boot 2.3 (sortie en mai 2020). Cela permet aux requêtes actives de se terminer avant de fermer le contexte et d'arrêter le conteneur.
À partir des notes de version :
L'arrêt progressif est pris en charge avec les quatre serveurs Web intégrés (Jetty, Reactor Netty, Tomcat et Undertow) et avec les applications Web réactives et basées sur des servlets. Lorsqu'il est activé à l'aide de
server.shutdown=graceful
, à l'arrêt, le serveur Web n'autorisera plus les nouvelles demandes et attendra une période de grâce pour que les demandes actives se terminent. La période de grâce peut être configurée à l'aide despring.lifecycle.timeout-per-shutdown-phase
.
Ainsi, lorsque l'arrêt progressif est activé, l'application exécutera les étapes suivantes de manière séquentielle lors de l'arrêt:
server.shutdown=graceful
, ajoutez server.shutdown=graceful
aux propriétés (par défaut, il est défini sur immediate
).spring.lifecycle.timeout-per-shutdown-phase
(exemple: spring.lifecycle.timeout-per-shutdown-phase=1m
.Pour Spring Boot <2.3, vous devrez bricoler le connecteur du serveur pour arrêter d'accepter de nouvelles demandes, comme expliqué dans ce problème Spring GitHub .
Avez-vous essayé ApplicationListener et context.close ()?
Ce lien pourrait-il vous aider ( dzone.com/articles/graceful-shutdown-spring-boot-applicatio ns )
afaik enregistrez simplement une méthode destroy pour toutes les ressources telles que jdbc, etc. et spring boot fera le reste pour vous lorsque vous supprimez simplement l'application à l'aide de la commande kill
@AnirudhSimha spring n'appelle pas les méthodes destroy sur le processus kill, elles n'appellent qu'après avoir invoqué la méthode close du contexte
J'ai fait la même chose avec l'aide de HA Proxy et Ansible. Mes étapes sont 1) activé la page d'attente donc plus de demande reçue 2) vérifier les journaux de service plus de rotation des 5 dernières minutes. 3) puis arrêt
@AlmasAbdrazak Non, je suppose que ce n'est pas la bonne façon.
@GovindParashar merci, le lien a été utile, mais c'est pour SpringBoot 2.0+, mais en tout cas merci!
@GovindParashar mais vous vous retrouvez avec ApplicationListener;)