Intercepter l’arrêt de la JVM
Avec l’objet Runtime
, il est possible d’ajouter des tâches exécutées au moment de l’arrêt de la JVM.
Runtime.getRuntime()
.addShutdownHook(
new Thread(() -> System.out.println("Cleaning before shutdown"))
);
Les signaux Linux
Pour arrêter sagement un process :
$ kill 1234
ou
$ kill -TERM 1234
Pour simuler un CTRL+C :
$ kill -INT 1234
ou
$ kill -2 1234
Quelques signaux :
-
HUP (1) : hangup
-
INT (2) : terminal interrupt (CTRL+C)
-
QUIT (3) : terminal quit, with core dump
-
KILL (9) : kill (cannot be caught)
-
TERM (15) : termination (default)
-
…
La plupart de ces signaux provoquent l’arrêt du process, avec éventuellement un core dump (QUIT, ILL, TRAP,…). Ce comportement par défaut peut être redéfini par le process. Seul le signal KILL ne peut pas être intercepté.
La liste complète des signaux peut être obtenue par la commande kill -l
.
Les signaux Linux en Java
Le signal QUIT est intercepté par le JVM pour générer un thread dump.
Il est possible de définir ses propres inteceptions avec la classe sun.misc.Signal
.
Signal.handle(
new Signal("INT"),
this::handleINT
);
Attention, le comportement est très différent des shutdown hooks.
En effet, ici on n’ajoute pas d’action mais on remplace l’action par défaut.
Par conséquent, si on veut que le process s’arrête, il faut le lui demander explicitement : System.exit(0)
.
Comme spécifié plus haut, KILL ne peut pas être intercepté. Si on essaie, ça déclenche une exception.
java.lang.IllegalArgumentException: Signal already used by VM or OS: SIGKILL
at java.base/jdk.internal.misc.Signal.handle(Signal.java:172)
at jdk.unsupported/sun.misc.Signal.handle(Signal.java:157)
at ...
Il est aussi possible d’envoyer un signal au process courant, à condition que celui-ci le gère :
Signal.raise(new Signal("HUP"));
Attention, la classe Elle existe depuis le JDK 1.2, et est toujours utilisable dans le JDK 17. Son support n’a été ajouté que tardivement dans GraalVM, en version 21.1. |
Avec Docker
A l’intérieur du conteneur, la principale subtilité vient du fait que l’application est souvent sur le process numéro 1 et qu’on ne peut pas lui adresser de signal KILL. Les autres signaux fonctionnent bien.
Depuis l’hôte, on peut transmettre un signal par la commande docker kill
.
Le signal par défaut, si on ne spécifie par --signal
, est KILL.
$ docker kill --signal=INT <container-name>