Configurer le service buggy systemd pour qu'il se termine via SIGKILL

20

Contexte

On m'a demandé de créer un systemdscript pour un nouveau service, foo_daemonqui se met parfois dans un "mauvais état" et ne mourra pas SIGTERM(probablement à cause du gestionnaire de signal personnalisé). Cela est problématique pour les développeurs, car ils sont invités à démarrer / arrêter / redémarrer le service via:

  • systemctl start foo_daemon.service
  • systemctl stop foo_daemon.service
  • systemctl restart foo_daemon.service

Problème

Parfois, en raison d' foo_daemonun mauvais état, nous devons le tuer de force via:

  • systemctl kill -s KILL foo_daemon.service

Question

Comment puis-je configurer mon systemdscript pour foo_daemonque, chaque fois qu'un utilisateur tente d'arrêter / redémarrer le service systemd:

  • Essayez d'arrêter gracieusement le foo_daemonvia SIGTERM.
  • Accordez jusqu'à 2 secondes pour que l'arrêt / l'arrêt foo_daemonse termine.
  • Essayez d'arrêter forcé foo_daemonvia SIGKILLsi le processus est toujours en cours (nous n'avons donc pas de risque de recyclage du PID et de systemdproblème SIGKILLavec le mauvais PID). L'appareil que nous testons génère / accélère de nombreux processus rapidement, il existe donc une préoccupation rare mais très réelle concernant le recyclage du PID, qui pose problème.
  • Si, dans la pratique, je suis juste paranoïaque à propos du recyclage des PID, je suis d'accord avec le script qui vient d'être émis SIGKILLcontre le PID du processus sans se soucier de tuer un PID recyclé.

Nuage
la source
2
Même si vous générez des processus assez rapidement pour rouler plus de 4 millions de PID en deux secondes, systemd ne reste pas dans une boucle vérifiant "ce pid est-il toujours vivant? Ce pid est-il toujours vivant?" parce qu'il n'en a pas besoin ; il est déjà informé si ses processus enfants immédiats sont toujours en vie ou non (au moyen de SIGCHLD ordinaire et waitpid ()). Donc, s'il voit que le processus s'est terminé après SIGTERM, il marquera simplement le service comme `` inactif '' à ce stade - il ne se souciera pas du tout de vérifier, d'attendre et d'envoyer le SIGKILL.
grawity

Réponses:

26

systemd prend déjà cela en charge et il est activé par défaut .

La seule chose que vous voudrez peut-être personnaliser est le délai d'attente, que vous pouvez utiliser TimeoutStopSec=. Par exemple:

[Service]
TimeoutStopSec=2

Maintenant, systemd enverra un SIGTERM, attendra deux secondes que le service se termine, et si ce n'est pas le cas, il enverra un SIGKILL.

Si votre service n'est pas compatible avec systemd, vous devrez peut-être fournir le chemin d'accès à son fichier PID avec PIDFile=.

Enfin, vous avez mentionné que votre démon engendre de nombreux processus. Dans ce cas, vous souhaiterez peut-être définir KillMode=control-groupet systemd enverra des signaux à tous les processus du groupe de contrôle.

Michael Hampton
la source
Merci. Une dernière question: supposons que le service ne soit pas compatible avec systemd. Que puis-je ajouter au script systemd pour ce service afin que systemd crée / gère le fichier PID? De plus, le service peut être multi-instance via des unités de modèle, donc nous le lançons généralement via `systemctl start [email protected]", donc cela aurait-il un impact sur la logique du fichier PID dans le script?
Cloud
4
@DevNull systemd ne crée ni ne gère les fichiers PID. Il n'y a aucune raison pour cela. Si votre service ne crée pas son propre fichier PID, configurez-le si possible pour qu'il s'exécute au premier plan (au lieu de démonifier) ​​et définissez-le Type=simpledans l'unité systemd.
Michael Hampton
1
Si le service a des dépendants, Type=forkinga l'avantage (si le service a été correctement écrit) d'informer systemd quand il est complètement «prêt», ce que Type = simple ne peut pas faire. Démoniser n'est pas un problème, même sans fichier PID - systemd suivra de toute façon le processus principal.
grawity
1
@grawity C'est vrai ... bien que d'après mon expérience, les services démonifient avant d'être réellement prêts à commencer à servir. Un service compatible avec Type=notifysystemd est préférable pour systemd, et de nombreux services communs le font déjà. Mais probablement pas ce service hérité. Dans le cas du PO, il dispose d'un service qui engendre de nombreux processus. Les documents systemd mettent en garde contre ce cas .
Michael Hampton
1

Étant donné que personne n'a mentionné le besoin Type=oneshot, voici un exemple complet qui se termine en raison d'un échec de temporisation.

[Unit]
Description=timeout test

[Service]
Type=oneshot
TimeoutStartSec=2
ExecStart=/bin/sleep 10
Evidlo
la source