web-dev-qa-db-fra.com

Dans quel ordre dois-je envoyer des signaux aux processus d'arrêt en douceur?

Dans un commentaire sur cette réponse d'une autre question , le commentateur dit:

n’utilisez pas kill -9 sauf si absolument nécessaire! SIGKILL ne peut pas être piégé, alors le programme tué ne peut exécuter aucun programme des routines d'arrêt, par exemple effacer fichiers temporaires. Commencez par essayer HUP (1), puis INT (2), puis QUIT (3)

Je suis d'accord en principe sur SIGKILL, mais le reste est une nouvelle pour moi. Étant donné que le signal par défaut envoyé par kill est SIGTERM, je suppose que c'est le signal le plus communément attendu pour l'arrêt en douceur d'un processus arbitraire. De plus, j'ai vu que SIGHUP était utilisé pour des raisons qui ne se terminaient pas, comme dire à un démon de "relire votre fichier de configuration". Et il me semble que SIGINT (la même interruption que celle que vous obtenez habituellement avec Ctrl-C, n'est-ce pas?) N'est pas aussi largement pris en charge que cela devrait être, ou se termine de manière plutôt ingrate.

Etant donné que SIGKILL est un dernier recours - Quels signaux et dans quel ordre, devriez-vous envoyer à un processus arbitraire afin de le fermer le plus gracieusement possible?

Veuillez justifier vos réponses avec des faits à l'appui (au-delà des préférences personnelles ou des opinions) ou des références, si vous le pouvez.

Remarque: je m'intéresse particulièrement aux meilleures pratiques qui prennent en compte bash/Cygwin.

Edit: Jusqu'à présent, personne ne semble parler d'INT ou de QUIT, et il est fait mention de HUP. Y a-t-il une raison pour les inclure dans un processus de mise à mort ordonné?

74
system PAUSE

SIGTERM indique à une application de se terminer. Les autres signaux indiquent à l'application d'autres choses qui ne sont pas liées à l'arrêt mais qui peuvent parfois avoir le même résultat. Ne les utilisez pas. Si vous souhaitez qu'une application soit fermée, dites-le-lui. Ne lui donnez pas de signaux trompeurs.

Certaines personnes croient que la manière standard intelligente de mettre fin à un processus consiste à lui envoyer un grand nombre de signaux, tels que HUP, INT, TERM et enfin KILL. C'est ridicule. SIGTERM est le bon signal de terminaison et si SIGTERM ne met pas fin au processus instantanément, comme vous préférez, c'est parce que l'application a choisi de gérer le signal. Ce qui signifie qu’il a une très bonne raison de ne pas terminer immédiatement: il a un travail de nettoyage à faire. Si vous interrompez ce travail de nettoyage avec d’autres signaux, vous ne saurez pas quelles données de la mémoire n’ont pas encore été sauvegardées sur le disque, quelles applications client sont laissées en suspens ou si vous l’interrompez au "milieu de la phrase", ce qui constitue effectivement une corruption des données.

Pour plus d'informations sur la signification réelle des signaux, voir sigaction (2). Ne confondez pas "Action par défaut" avec "Description", ils ne sont pas la même chose.

SIGINT est utilisé pour signaler une "interruption de clavier" interactive du processus. Certains programmes peuvent gérer la situation de manière particulière pour les utilisateurs de terminaux.

SIGHUP est utilisé pour signaler que le terminal a disparu et ne regarde plus le processus. C'est tout. Certains processus choisissent de s’arrêter en réponse, généralement parce que leur fonctionnement n’a aucun sens sans un terminal. Certains choisissent d’effectuer d’autres tâches, telles que la revérification des fichiers de configuration.

SIGKILL est utilisé pour supprimer de force le processus du noyau. C'est spécial en ce sens que ce n'est pas réellement un signal au processus mais est plutôt interprété directement par le noyau.

N'envoyez pas SIGKILL. SIGKILL ne devrait certainement jamais être envoyé par des scripts. Si l'application gère le SIGTERM, le nettoyage peut prendre une seconde, cela peut prendre une minute, cela peut prendre une heure. En fonction de ce que l'application doit être faite avant qu'elle soit prête à se terminer. Toute logique selon laquelle " suppose " la séquence de nettoyage d'une application a pris suffisamment de temps et doit être raccourcie ou SIGKILLed après X secondes est tout simplement faux.

La seule raison pour laquelle une application aurait besoin d'un SIGKILL pour se terminer, c'est si un bogue a été détecté pendant sa séquence de nettoyage. Dans ce cas, vous pouvez ouvrir un terminal et le SIGKILL manuellement. En dehors de cela, la seule autre raison pour laquelle vous voulez SIGKILL quelque chose est parce que vous VOULEZ pour l'empêcher de se nettoyer.

Même si la moitié du monde envoie aveuglément SIGKILL au bout de 5 secondes, c'est toujours une mauvaise chose à faire.

101
lhunath

Réponse courte: envoyez SIGTERM, 30 secondes plus tard, SIGKILL. C’est-à-dire que vous envoyez SIGTERM, attendez un peu (cela peut varier d’un programme à l’autre, vous connaissez peut-être mieux votre système, mais 5 à 30 secondes suffisent. Lorsqu’une machine est éteinte, elle peut automatiquement attendre jusqu’à 1h30. Pourquoi se dépêcher, après tout?), Alors envoyez SIGKILL.

Réponse raisonnable: SIGTERM, SIGINT, SIGKILL C'est plus que suffisant. Le processus very sera probablement terminé avant SIGKILL.

Réponse longue: SIGTERM, SIGINT, SIGQUIT, SIGABRT, SIGKILL

C'est inutile, mais au moins vous ne trompez pas le processus concernant votre message. Tous ces signaux do signifient que vous voulez que le processus arrête ce qu'il est en train de faire et quitte. 

Peu importe la réponse que vous choisissez parmi cette explication, gardez cela à l'esprit! 

Si vous envoyez un signal qui signifie autre chose, le processus peut le traiter de manière très différente (d'une part). D'un autre côté, si le processus ne gère pas le signal, peu importe ce que vous envoyez, le processus sera quand même arrêté (lorsque l'action par défaut doit se terminer, bien sûr).

Donc, vous devez penser comme vous en tant que programmeur. Coderiez-vous un gestionnaire de fonctions pour, disons, SIGHUP pour quitter un programme qui se connecte à quelque chose, ou le feriez-vous en boucle pour essayer de vous reconnecter? C'est la principale question ici! C'est pourquoi il est important de simplement envoyer des signaux qui signifient ce que vous souhaitez.

Réponse presque stupide:

Le tableau ci-dessous contient les signaux pertinents et les actions par défaut si le programme ne les gère pas.

Je les ai commandés dans l’ordre que je suggère d’utiliser (BTW, je vous suggère d’utiliser la réponse raisonnable}, et non celle-ci ici), si vous avez vraiment besoin de toutes les essayer (ce serait amusant de dire les table est classée en fonction de la destruction qu’elle peut causer, mais ce n’est pas complètement vrai). 

Les signaux suivis d'un astérisque (*) ne sont pas recommandés _. L'important est que vous ne sachiez peut-être jamais ce qu'il est programmé de faire. Spécialement SIGUSR! Cela peut commencer l’apocalipse (c’est un signal gratuit pour un programmeur qui fait ce qu’il veut!). Mais, s'il n'est pas traité OU dans le cas peu probable où il est géré de se terminer, le programme se terminera.

Dans le tableau, les signaux avec les options par défaut pour terminer et générer un vidage de mémoire sont conservés, juste avant SIGKILL.

Signal     Value     Action   Comment
----------------------------------------------------------------------
SIGTERM      15       Term    Termination signal
SIGINT        2       Term    Famous CONTROL+C interrupt from keyboard
SIGHUP        1       Term    Disconnected terminal or parent died
SIGPIPE      13       Term    Broken pipe
SIGALRM(*)   14       Term    Timer signal from alarm
SIGUSR2(*)   12       Term    User-defined signal 2
SIGUSR1(*)   10       Term    User-defined signal 1
SIGQUIT       3       Core    CONTRL+\ or quit from keyboard
SIGABRT       6       Core    Abort signal from abort(3)
SIGSEGV      11       Core    Invalid memory reference
SIGILL        4       Core    Illegal Instruction
SIGFPE        8       Core    Floating point exception
SIGKILL       9       Term    Kill signal

Ensuite, je suggèrerais pour cette longue réponse presque stupide: SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGQUIT, SIGABRT, SIGKILL

Et finalement, le 

Absolument stupide Long Long Réponse:

N'essayez pas ca a la maison.

SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGALRM, SIGUSR2, SIGUSR1, SIGQUIT, SIGABRT, SIGSEGV, SIGILL, SIGFPE et si rien ne fonctionnait, SIGKILL.

SIGUSR2 devrait être essayé avant SIGUSR1 car nous nous en porterions mieux si le programme ne gère pas le signal. Et il est beaucoup plus probable qu'il gère SIGUSR1 s'il ne gère qu'un seul d'entre eux.

BTW, the KILL: il n’est pas faux d’envoyer SIGKILL à un processus, comme l’indique une autre réponse. Eh bien, imaginez ce qui se passe lorsque vous envoyez une commande shutdown? Il essaiera SIGTERM et SIGKILL uniquement. Pourquoi pensez-vous que c'est le cas? Et pourquoi avez-vous besoin d'autres signaux si la même commande shutdown n'utilise que ces deux-là?


Revenons maintenant à la longue réponse, il s’agit d’un bon oneliner:

for SIG in 15 2 3 6 9 ; do echo $SIG ; echo kill -$SIG $PID || break ; sleep 30 ; done

Il dort pendant 30 secondes entre les signaux. Pourquoi auriez-vous besoin d'un oneliner? ;)

Aussi, recommandé: essayez-le avec uniquement les signaux 15 2 9 de la réponse raisonnable

sécurité: supprimez le deuxième echo lorsque vous êtes prêt à partir. Je l'appelle mon dry-run pour en ligne. Toujours l'utiliser pour tester.


Script killgracefully

En fait, cette question m'a tellement intriguée que j'ai décidé de créer un petit script pour le faire. N'hésitez pas à le télécharger (cloner) ici:

Lien GitHub vers Killgracefully repository

7
Dr Beco

En règle générale, vous envoyez SIGTERM, la valeur par défaut de kill. C'est le défaut pour une raison. Si seulement un programme ne s’arrête pas dans un délai raisonnable, vous devriez recourir à SIGKILL. Mais notez qu'avec SIGKILL, le programme n'a aucune possibilité de nettoyer les données et les données pourraient être corrompues.

En ce qui concerne SIGHUP, HUP signifie "raccrocher" et signifiait historiquement que le modem était déconnecté. C'est essentiellement équivalent à SIGTERM. La raison pour laquelle les démons utilisent parfois SIGHUP pour redémarrer ou recharger la configuration est que les démons se détachent de tout terminal de contrôle car un démon n'en a pas besoin et ne recevrait donc jamais SIGHUP; Tous les démons ne l'utilisent pas pour recharger! L'action par défaut pour SIGHUP est de se terminer et de nombreux démons se comportent de cette façon! Vous ne pouvez donc pas envoyer aveuglément SIGHUPs à des démons et vous attendre à ce qu'ils survivent.

Edit: SIGINT est probablement inapproprié pour mettre fin à un processus, car il est normalement lié à ^C ou à tout paramètre du terminal permettant d'interrompre un programme. De nombreux programmes capturent cela pour leurs propres besoins, il est donc assez courant que cela ne fonctionne pas. SIGQUIT a généralement pour défaut de créer un vidage principal, et à moins que vous ne souhaitiez que les fichiers centraux soient stockés, ce n'est pas non plus un bon candidat.

Résumé: si vous envoyez SIGTERM et que le programme ne meurt pas dans votre délai, envoyez-le SIGKILL.

6
dwc

SIGTERMsignifie en réalité envoyer à une application un message: "voudriez-vous être si gentil et vous suicider" Il peut être intercepté et traité par l'application pour exécuter le code de nettoyage et d'arrêt.

SIGKILLne peut pas être intercepté par une application. L'application est éliminée par le système d'exploitation sans aucune possibilité de nettoyage.

Il est typique d’envoyer SIGTERM d’abord, de dormir un peu, puis d’envoyer SIGKILL.

5
vartec
  • SIGTERM équivaut à "cliquer sur le" X "" dans une fenêtre.
  • SIGTERM est ce que Linux utilise en premier, lorsqu’il est en train de s’arrêter.
3
gbarry

Avec toute la discussion en cours ici, aucun code n'a été proposé. Voici ma prise:

#!/bin/bash

$pid = 1234

echo "Killing process $pid..."
kill $pid

waitAttempts=30 
for i in $(seq 1 $waitAttempts)
do
    echo "Checking if process is alive (attempt #$i / $waitAttempts)..."
    sleep 1

    if ps -p $pid > /dev/null
    then
        echo "Process $pid is still running"
    else
        echo "Process $pid has shut down successfully"
        break
    fi
done

if ps -p $pid > /dev/null
then
    echo "Could not shut down process $pid gracefully - killing it forcibly..."
    kill -SIGKILL $pid
fi
1
Ohad Schneider

HUP ressemble à des ordures pour moi. Je l'enverrais pour qu'un démon relise sa configuration.

SIGTERM peut être intercepté; vos démons pourraient bien avoir du code de nettoyage à exécuter lorsqu'ils recevront ce signal. Vous ne pouvez pas faire cela pour SIGKILL. Ainsi, avec SIGKILL, vous ne donnez aucune option à l'auteur du démon. 

Plus à ce sujet sur Wikipedia

0
innaM