Configurare il servizio buggy systemd per terminare tramite SIGKILL


20

sfondo

Mi è stato chiesto di creare uno systemdscript per un nuovo servizio, foo_daemonche a volte entra in "cattivo stato" e non morirà via SIGTERM(probabilmente a causa del gestore di segnale personalizzato). Ciò è problematico per gli sviluppatori, in quanto sono tenuti ad avviare / arrestare / riavviare il servizio tramite:

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

Problema

A volte, a causa del foo_daemoncattivo stato, dobbiamo ucciderlo forzatamente tramite:

  • systemctl kill -s KILL foo_daemon.service

Domanda

Come posso impostare il mio systemdscript in foo_daemonmodo che, ogni volta che un utente tenta di arrestare / riavviare il servizio, systemdpossa:

  • Tentare un arresto graduale di foo_daemonvia SIGTERM.
  • Dare fino a 2 secondi per il completamento dell'arresto / chiusura foo_daemon.
  • Tentare un arresto forzato della foo_daemonvia SIGKILL, se il processo è ancora in vita (in modo da non abbiamo il rischio che la PID essere riciclati e systemdproblemi SIGKILLcontro il PID sbagliato). Il dispositivo che stiamo testando genera / procede rapidamente a numerosi processi, quindi esiste una preoccupazione rara ma molto reale sul riciclaggio del PID che causa un problema.
  • Se, in pratica, sono solo paranoico sul riciclaggio dei PID, sto bene con lo script che emette solo SIGKILLcontro il processo 'PID senza preoccuparsi di uccidere un PID riciclato.


2
Anche se si generano processi abbastanza rapidamente da superare i 4 milioni di PID in due secondi, systemd non si siede in un ciclo di verifica "questo pid è ancora vivo? È ancora vivo?" perché non è necessario ; è già informato se i suoi processi figlio immediati sono ancora vivi o meno (tramite SIGCHLD ordinario e waitpid ()). Quindi, se vede che il processo è terminato dopo SIGTERM, segnerà semplicemente il servizio come 'inattivo' a quel punto - non si preoccuperà affatto di controllare, attendere e inviare SIGKILL.
Grawity,

Risposte:


26

systemd lo supporta già immediatamente, ed è abilitato di default .

L'unica cosa che potresti voler personalizzare è il timeout, che puoi fare con TimeoutStopSec=. Per esempio:

[Service]
TimeoutStopSec=2

A questo punto systemd invierà un SIGTERM, attenderà due secondi per la chiusura del servizio e, in caso contrario, invierà un SIGKILL.

Se il servizio non è compatibile con systemd, potrebbe essere necessario fornire il percorso del file PID con PIDFile=.

Infine, hai detto che il tuo demone genera molti processi. In questo caso, potresti voler impostare KillMode=control-groupe systemd invierà segnali a tutti i processi nel cgroup.


Grazie. Un'ultima domanda: supponiamo che il servizio non sia compatibile con systemd. Cosa posso aggiungere allo script systemd per questo servizio in modo che systemd crei / gestisca il file PID? Inoltre, il servizio può essere a più istanze tramite unità modello, quindi in genere lo avviamo tramite `systemctl start foo_dameon@1.service", in modo da avere un impatto sulla logica del file PID nello script?
Cloud

4
@DevNull systemd non crea o gestisce file PID. Non c'è motivo per farlo. Se il tuo servizio non crea il proprio file PID, se possibile configuralo per essere eseguito in primo piano (anziché daemonizzare) e impostato Type=simplenell'unità systemd.
Michael Hampton

1
Se il servizio ha delle dipendenze, Type=forkingha il vantaggio di (se il servizio è stato scritto correttamente) di informare systemd quando è completamente 'pronto' che Type = simple non può fare. La demonizzazione non è un problema, anche senza un file PID - systemd rintraccia comunque il processo principale.
Grawity,

1
@grawity Abbastanza vero ... anche se è stata la mia esperienza che i servizi si demonizzano prima che siano effettivamente pronti per iniziare a servire. Un servizio compatibile con systemd Type=notifyè il migliore per systemd e molti servizi comuni lo fanno già. Ma probabilmente non questo servizio legacy. Nel caso del PO, ha un servizio che genera molti processi. I documenti di sistema avvisano di questo caso .
Michael Hampton

1

Poiché nessuno ha menzionato la necessità Type=oneshot, ecco un esempio completo che esce a causa di un errore di timeout.

[Unit]
Description=timeout test

[Service]
Type=oneshot
TimeoutStartSec=2
ExecStart=/bin/sleep 10
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.