Configure o serviço systemd com erros para finalizar via SIGKILL


20

fundo

Me pediram para criar um systemdscript para um novo serviço, foo_daemonque às vezes entra em "estado ruim" e não morre SIGTERM(provavelmente devido ao manipulador de sinal personalizado). Isso é problemático para os desenvolvedores, pois eles são instruídos a iniciar / parar / reiniciar o serviço via:

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

Problema

Às vezes, devido a foo_daemonentrar em um estado ruim, temos que matá-lo à força via:

  • systemctl kill -s KILL foo_daemon.service

Questão

Como posso configurar meu systemdscript para foo_daemonque, sempre que um usuário tentar parar / reiniciar o serviço systemd,:

  • Tente desligar normalmente a foo_daemonvia SIGTERM.
  • Dê até 2 segundos para que o desligamento / término foo_daemonseja concluído.
  • Tente desligar a foo_daemonvia SIGKILLse o processo ainda estiver ativo (portanto, não corremos o risco de o PID ser reciclado e systemdproblemas SIGKILLcom o PID errado). O dispositivo que estamos testando gera / bifurca-se rapidamente em vários processos, portanto , existe uma preocupação rara, mas muito real, com a reciclagem de PID, causando um problema.
  • Se, na prática, estou apenas paranóico com a reciclagem de PID, estou bem com o script emitido SIGKILLcontra o PID do processo sem me preocupar em matar um PID reciclado.


2
Mesmo se você gerar processos com rapidez suficiente para rolar mais de 4 milhões de PIDs em dois segundos, o systemd não ficará parado verificando "esse pid ainda está vivo? Este pid ainda está vivo?" porque não precisa ; já é informado se seus processos filhos imediatos ainda estão vivos ou não (por meio do SIGCHLD comum e do waitpid ()). Portanto, se perceber que o processo foi encerrado após o SIGTERM, ele simplesmente marcará o serviço como 'inativo' naquele momento - não se preocupará em verificar, aguardar e enviar o SIGKILL.
grawity

Respostas:


26

O systemd já suporta isso imediatamente e é ativado por padrão .

A única coisa que você pode querer personalizar é o tempo limite, com o qual você pode fazer TimeoutStopSec=. Por exemplo:

[Service]
TimeoutStopSec=2

Agora, o systemd enviará um SIGTERM, aguarde dois segundos para o serviço sair e, se não o fizer, enviará um SIGKILL.

Se o seu serviço não estiver ciente do sistema, talvez seja necessário fornecer o caminho para o arquivo PID PIDFile=.

Por fim, você mencionou que seu daemon gera muitos processos. Nesse caso, você pode querer configurar KillMode=control-groupe o systemd enviará sinais para todos os processos no cgroup.


Obrigado. Uma última pergunta: vamos assumir que o serviço não reconhece o systemd. O que eu poderia adicionar ao script systemd deste serviço para que o systemd crie / gerencie o arquivo PID? Além disso, o serviço pode ser de várias instâncias por meio de unidades de modelo, portanto, normalmente o iniciamos através de `systemctl start foo_dameon@1.service", para que isso impactasse a lógica do arquivo PID no script?
Cloud

4
O @DevNull systemd não cria nem gerencia arquivos PID. Não há razão para isso. Se o seu serviço não criar seu próprio arquivo PID, se possível, configure-o para ser executado em primeiro plano (em vez de daemonização) e definido Type=simplena unidade systemd.
Michael Hampton

11
Se o serviço tiver dependentes, Type=forkingtem a vantagem de (se o serviço foi escrito corretamente) informar o systemd quando estiver totalmente 'pronto', o que Type = simple não pode fazer. Daemonizing não é um problema, mesmo sem um arquivo PID - o systemd rastreará o processo principal de qualquer maneira.
grawity

11
@ grrawity É verdade ... embora tenha sido minha experiência que os serviços daemonize antes de estarem realmente prontos para começar a servir. Um serviço que reconhece o systemd Type=notifyé o melhor para o systemd, e muitos serviços comuns já fazem isso. Mas provavelmente não esse serviço legado. No caso do OP, ele possui um serviço que gera muitos processos. Os documentos do systemd alertam sobre esse caso .
Michael Hampton

1

Como ninguém mencionou a necessidade Type=oneshot, aqui está um exemplo completo que sai devido a uma falha de tempo limite.

[Unit]
Description=timeout test

[Service]
Type=oneshot
TimeoutStartSec=2
ExecStart=/bin/sleep 10
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.