Question Comment arrêter une application Spring Boot de manière correcte?


Dans le document d'amorçage Spring, ils ont déclaré que «chaque SpringApplication enregistre un hook d'arrêt avec la machine virtuelle Java pour garantir que l'application ApplicationContext se ferme normalement à la sortie».

Quand je clique ctrl+c sur la commande shell, l'application peut être arrêtée avec élégance. Si je lance l'application sur une machine de production, je dois utiliser la commande java -jar ProApplicaton.jar. Mais je ne peux pas fermer le terminal shell, sinon il va fermer le processus.

Si je lance la commande comme nohup java -jar ProApplicaton.jar &, Je ne peux pas utiliser ctrl+c pour l'éteindre gracieusement.

Quelle est la manière correcte de démarrer et d'arrêter une application Spring Boot dans l'environnement de production?


75
2017-10-24 12:05


origine


Réponses:


Si vous utilisez le module d'actionneur, vous pouvez arrêter l'application via JMX ou HTTP si le noeud final est activé (ajouter endpoints.shutdown.enabled=true à ton application.properties fichier).

/shutdown - Permet à l'application d'être arrêtée normalement (non activée par défaut).

Selon la manière dont un noeud final est exposé, le paramètre sensible peut être utilisé comme un indicateur de sécurité. Par exemple, les terminaux sensibles nécessiteront un nom d’utilisateur / mot de passe lorsqu’ils y accèdent. HTTP (ou simplement désactivé si la sécurité Web n'est pas activée).

Du Documentation de démarrage du printemps


45
2017-10-25 14:14



En ce qui concerne la réponse de Jean-Philippe Bond,

Voici un exemple rapide maven pour l'utilisateur maven pour configurer le point de terminaison HTTP pour arrêter une application Web de démarrage à partir du printemps à l'aide de Spring-Boot-Starter-Actuator afin de pouvoir copier et coller:

1.avoir pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2.application.properties:

#No auth  protected 
endpoints.shutdown.sensitive=false

#Enable shutdown endpoint
endpoints.shutdown.enabled=true

Tous les points de terminaison sont listés ici:

3.Envoyez une méthode de publication pour arrêter l'application:

curl -X POST localhost:port/shutdown

Note de sécurité:

si vous avez besoin de la méthode d’arrêt protégée par l’authentification, vous pouvez aussi avoir besoin de

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

configurer les détails:


40
2018-03-29 05:00



Vous pouvez créer l'application springboot pour écrire le PID dans le fichier et vous pouvez utiliser le fichier pid pour arrêter ou redémarrer ou obtenir le statut à l'aide d'un script bash. Pour écrire le PID dans un fichier, enregistrez un écouteur à SpringApplication à l'aide d'ApplicationPidFileWriter comme indiqué ci-dessous:

SpringApplication application = new SpringApplication(Application.class);
application.addListeners(new ApplicationPidFileWriter("./bin/app.pid"));
application.run();

Ensuite, écrivez un script bash pour exécuter l'application de démarrage à ressort. Référence.

Vous pouvez maintenant utiliser le script pour démarrer, arrêter ou redémarrer.


24
2018-01-19 11:05



Voici une autre option qui ne nécessite pas de modifier le code ou d'exposer un point de terminaison d'arrêt. Créez les scripts suivants et utilisez-les pour démarrer et arrêter votre application.

start.sh

#!/bin/bash
java -jar myapp.jar & echo $! > ./pid.file &

Démarre votre application et enregistre l'identifiant du processus dans un fichier

stop.sh

#!/bin/bash
kill $(cat ./pid.file)

Arrête votre application en utilisant l'ID de processus enregistré

start_silent.sh

#!/bin/bash
nohup ./start.sh > foo.out 2> foo.err < /dev/null &

Si vous devez démarrer l'application à l'aide de ssh à partir d'une machine distante ou d'un pipeline CI, utilisez plutôt ce script pour démarrer votre application. Utiliser directement start.sh peut laisser le shell se bloquer.

Après par exemple re / déploiement de votre application, vous pouvez le redémarrer en utilisant:

sshpass -p password ssh -oStrictHostKeyChecking=no userName@www.domain.com 'cd /home/user/pathToApp; ./stop.sh; ./silent_start.sh'

19
2018-06-16 13:11



Spring Boot a fourni plusieurs écouteurs d'applications en essayant de créer un contexte d'application dont ApplicationFailedEvent. Nous pouvons utiliser pour connaître le contexte d'application initialisé ou non.

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.boot.context.event.ApplicationFailedEvent; 
    import org.springframework.context.ApplicationListener;

    public class ApplicationErrorListener implements 
                    ApplicationListener<ApplicationFailedEvent> {

        private static final Logger LOGGER = 
        LoggerFactory.getLogger(ApplicationErrorListener.class);

        @Override
        public void onApplicationEvent(ApplicationFailedEvent event) {
           if (event.getException() != null) {
                LOGGER.info("!!!!!!Looks like something not working as 
                                expected so stoping application.!!!!!!");
                         event.getApplicationContext().close();
                  System.exit(-1);
           } 
        }
    }

Ajouter à la classe d'écouteur ci-dessus à SpringApplication.

    new SpringApplicationBuilder(Application.class)
            .listeners(new ApplicationErrorListener())
            .run(args);  

3
2017-09-01 11:52



À partir de Spring Boot 1.5, il n'y a pas de mécanisme d'arrêt élégant et prêt à l'emploi. Certains démarreurs à ressort fournissent cette fonctionnalité:

  1. https://github.com/jihor/hiatus-spring-boot
  2. https://github.com/gesellix/graceful-shutdown-spring-boot
  3. https://github.com/corentin59/spring-boot-graceful-shutdown

Je suis l'auteur de nr. 1. Le starter est nommé "Hiatus for Spring Boot". Cela fonctionne au niveau de l'équilibreur de charge, c'est-à-dire simplement marque le service comme OUT_OF_SERVICE, sans interférer avec le contexte d'application d'aucune façon. Cela permet de procéder à un arrêt progressif et, si nécessaire, de mettre le service hors service pendant un certain temps et de le ramener à la vie. L'inconvénient est qu'il n'arrête pas la JVM, vous devrez le faire avec kill commander. Comme je dirige tout dans des conteneurs, ce n'était pas une grosse affaire pour moi, car je vais devoir arrêter et retirer le conteneur de toute façon.

Nos 2 et 3 sont plus ou moins basés sur ce post par Andy Wilkinson. Ils fonctionnent à sens unique - une fois déclenchés, ils finissent par fermer le contexte.


2
2017-09-29 13:29



SpringApplication enregistre implicitement un hook d'arrêt avec la machine virtuelle Java pour s'assurer que ApplicationContext est fermé correctement à la sortie. Cela appellera également toutes les méthodes de haricot annotées avec @PreDestroy. Cela signifie que nous ne devons pas utiliser explicitement le registerShutdownHook() méthode d'un ConfigurableApplicationContext dans une application de démarrage, comme nous devons le faire dans l'application de base de printemps.

@SpringBootConfiguration
public class ExampleMain {
    @Bean
    MyBean myBean() {
        return new MyBean();
    }

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(ExampleMain.class, args);
        MyBean myBean = context.getBean(MyBean.class);
        myBean.doSomething();

        //no need to call context.registerShutdownHook();
    }

    private static class MyBean {

        @PostConstruct
        public void init() {
            System.out.println("init");
        }

        public void doSomething() {
            System.out.println("in doSomething()");
        }

        @PreDestroy
        public void destroy() {
            System.out.println("destroy");
        }
    }
}

2
2018-04-10 07:00



Toutes les réponses semblent manquer le fait que vous devrez peut-être compléter une partie du travail de manière coordonnée lors d'un arrêt normal (par exemple, dans une application d'entreprise).

@PreDestroy vous permet d'exécuter du code d'arrêt dans les beans individuels. Quelque chose de plus sophistiqué ressemblerait à ceci:

@Component
public class ApplicationShutdown implements ApplicationListener<ContextClosedEvent> {
     @Autowired ... //various components and services

     @Override
     public void onApplicationEvent(ContextClosedEvent event) {
         service1.changeHeartBeatMessage(); // allows loadbalancers & clusters to prepare for the impending shutdown
         service2.deregisterQueueListeners();
         service3.finishProcessingTasksAtHand();
         service2.reportFailedTasks();
         service4.gracefullyShutdownNativeSystemProcessesThatMayHaveBeenLaunched(); 
         service1.eventLogGracefulShutdownComplete();
     }
}

1
2018-06-04 23:58