web-dev-qa-db-fra.com

Pas de SIGTERM avant SIGKILL / shutdown avec systemd sur Ubuntu 16.04

J'ai rencontré ce problème alors que j'essayais de répondre à une question sur Stackoverflow .

À l’arrêt, Ubuntu 12.04 envoie SIGTERM à tous les processus et attend au plus 10 secondes avant de les tuer avec SIGKILL (sauf s’ils se sont arrêtés avant). Ma réponse à SO contient même un script Python qui vérifie ce comportement. Le script est démarré dans un terminal, envoyé en arrière-plan et désavoué par le terminal. Lors de la réception de SIGTERM, le script continue de fonctionner et affiche continuellement dans un fichier la durée de son exécution après réception de SIGTERM.

Ubuntu 16.04 cependant, le script est tué immédiatement à l’arrêt (aucun SIGTERM n’est enregistré).

J'ai cherché sur Google pendant un moment, mais je n'ai rien trouvé d'utile. Est-ce que personne n'a jamais rencontré ce changement radical pour la version actuelle de LTS?

Voici le script signaltest.py

import signal
import time

stopped = False

out = open('log.txt', 'w')

def stop(sig, frame):
    global stopped
    stopped = True
    out.write('caught SIGTERM\n')
    out.flush()

signal.signal(signal.SIGTERM, stop)

while not stopped:
    out.write('running\n')
    out.flush()
    time.sleep(1)

stop_time = time.time()
while True:
    out.write('%.4fs after stop\n' % (time.time() - stop_time))
    out.flush()
    time.sleep(0.1)

Le script utilise le fichier log.txt dans le répertoire en cours pour toutes les sorties. Il a une boucle qui affiche "en cours" chaque seconde. Recevoir SIGTERM interrompt la boucle et lance une autre boucle qui affiche les secondes écoulées depuis la réception de SIGTERM.

Le script est exécuté à partir d'un terminal détaché à l'aide de disown:

python signaltest.py &
disown

Juste pour être clair: Ceci n'est pas un doublon de buntu n'envoie pas de SIGTERM à l'arrêt . La question concerne les applications de bureau et les réponses ne correspondent pas non plus.

1
code_onkel

systemd (opposé à upstart dans les versions précédentes d'Ubuntu) envoie en outre SIGHUP à l'arrêt (et attend 90 secondes au lieu de 10 avant d'envoyer SIGKILL). Je suggère d'ignorer SIGHUP ou de traiter SIGTERM et SIGHUP de la même manière (idempotente).

Le script de test modifié pourrait être modifié comme suit:

import signal
import time

stopped = False

out = open('log.txt', 'w')

def stop(sig, frame):
    global stopped
    stopped = True
    out.write('caught SIGTERM\n')
    out.flush()

def ignore(sig, frsma):
    out.write('ignoring signal %d\n' % sig)
    out.flush()

signal.signal(signal.SIGTERM, stop)
signal.signal(signal.SIGHUP, ignore)

while not stopped:
    out.write('running\n')
    out.flush()
    time.sleep(1)

stop_time = time.time()
while True:
    out.write('%.4fs after stop\n' % (time.time() - stop_time))
    out.flush()
    time.sleep(0.1)
3
code_onkel