Qual PID pertence à seção PIDFile systemd ao criar um daemon de script de shell?

1

Eu criei um daemon de script de shell, com base no código de esta resposta . Eu escrevi um arquivo de serviço systemd com o seguinte conteúdo:

[Unit]
Description=My Daemon
After=network.target

[Service]
Type=forking
PIDFile=/run/daemon.pid
ExecStart=/root/bin/daemon.sh
ExecReload=/bin/kill -1 -- $MAINPID
ExecStop=/bin/kill -- $MAINPID
TimeoutStopSec=5
KillMode=process

[Install]
WantedBy=multi-user.target

Pouco antes de iniciar o loop while, estou criando um arquivo PID (ele será criado pelo daemon, não pelo filho ou pelo pai, porque eles não chegam a este ponto): echo $$ > /run/daemon.pid; . Funciona bem, mas cada vez que eu chamo systemctl status daemon.service , recebo o seguinte aviso:

daemon.service: PID file /run/daemon.pid not readable (yet?) after start: No such file or directory

Se eu inserir a instrução PID creaton echo $$ > /run/daemon.pid; no início do script (que será usado pelos filhos e pai também), recebo o seguinte aviso:

daemon.service: PID 30631 read from file /run/daemon.pid does not exist or is a zombie.

Qual seria a melhor abordagem para criar o arquivo PID sem receber nenhuma mensagem de aviso pelo systemd?

    
por chevallier 03.08.2018 / 14:53

2 respostas

1

Portanto, o problema que você está vendo aqui é porque quando Type=forking está em uso, o arquivo pid deve ser criado (com o pid correto) antes que o processo pai saia.

Se você criar o pidfile do filho, ele irá correr com a saída do pai e, em alguns (muitos?) casos, o primeiro erro será visto.

Se você criar o pidfile escrevendo $$ antes de iniciar o filho, ele terá o pid do pai, que será encerrado, para que você veja o outro erro.

Uma maneira de fazer isso corretamente é escrever o pidfile do pai, logo antes de sair. Nesse caso, escreva $! (e não $$ ), que retorna o pid do último processo gerado em segundo plano.

Por exemplo:

#!/bin/bash

# Run the following code in background:
(
    while keep_running; do
        do_something
    done
) &

# Write pid of the child to the pidfile:
echo "$!" >/run/daemon.pid
exit

Isso deve funcionar corretamente ... CONTUDO , há uma maneira muito melhor de conseguir isso! Leia em ...

Na verdade, o ponto inteiro do systemd é para daemonizar processos e executá-los em segundo plano para você ... Ao tentar fazer isso sozinho, você está apenas evitando que o systemd faça isso por você. O que está tornando a sua vida muito mais difícil ao mesmo tempo ...

Em vez de usar Type=forking , basta escrever seu script de shell para executar em primeiro plano e configurar o serviço para usar Type=simple . Você não precisa de nenhum pidfiles então.

Atualize seu /root/bin/daemon.sh para simplesmente fazer isso:

#!/bin/bash

# Run the following code in foreground:
while keep_running; do
    do_something
done

(NOTA: Talvez daemon.sh não seja o melhor nome para ele neste momento ... Desde que isso implicaria que ele é executado em segundo plano. Talvez nomeie algo mais apropriado, relacionado ao que ele realmente faz.)

Em seguida, atualize o arquivo .service para usar Type=simple (que, na verdade, seria usado por padrão aqui, então você pode até omiti-lo.)

[Service]
Type=simple
ExecStart=/root/bin/daemon.sh
ExecReload=/bin/kill -1 -- $MAINPID
ExecStop=/bin/kill -- $MAINPID
TimeoutStopSec=5
KillMode=process

BTW, você provavelmente pode derrubar ExecStop= , já que matar o processo com um sinal também é o comportamento padrão ...

O Type=forking do systemd está realmente lá apenas para programas legados que só funcionam dessa maneira e não podem ser facilmente corrigidos para trabalhar em primeiro plano ... É hacky e ineficiente. O ponto principal do systemd (e algumas de suas alternativas, predecessores) é fazer o bifurcação e a daemonização em si e deixar os serviços se preocuparem em fazer o que precisam fazer! : -)

Espero que você ache isto útil ... E eu realmente espero que você escolha deixar o systemd fazer o trabalho pesado para você! É muito mais eficiente assim.

    
por 04.08.2018 / 06:28
0

Ok, a mensagem de erro daemon.service: PID file /run/daemon.pid not readable (yet?) after start: No such file or directory desapareceu depois que adicionei a seguinte instrução ao arquivo de serviço:

ExecStartPost=/bin/sleep 2
    
por 03.08.2018 / 15:23