Confundindo o comportamento do sistema com OnFailure = e Restart =

2

Estou usando o systemd 231 em um sistema embarcado e estou tentando criar um serviço que monitore um componente de hardware no sistema. Aqui está uma descrição aproximada do que estou tentando fazer:

  1. Quando o serviço, foo.service , é iniciado, ele inicia um aplicativo, foo_app .
  2. foo_app monitora o componente de hardware, executando continuamente.
  3. Se foo_app detectar uma falha de hardware, ela sairá com um código de retorno igual a 1. Isso deve acionar uma reinicialização do sistema.
  4. Se foo_app falhar, o systemd deverá reiniciar foo_app .
  5. Se foo_app repetidamente falhar, o systemd deve reinicializar o sistema.

Aqui está minha tentativa de implementar isso como um serviço:

[Unit]
Description=Foo Hardware Monitor

# If the application fails 3 times in 30 seconds, something has gone wrong,
# and the state of the hardware can't be guaranteed. Reboot the system here.
StartLimitBurst=3
StartLimitIntervalSec=30
StartLimitAction=reboot

# StartLimitAction=reboot will reboot the box if the app fails repeatedly,
# but if the app exits voluntarily, the reboot should trigger immediately
OnFailure=systemd-reboot.service

[Service]
ExecStart=/usr/bin/foo_app

# If the app fails from an abnormal condition (e.g. crash), try to
# restart it (within the limits of StartLimit*).
Restart=on-abnormal

Da documentação ( systemd.service e systemd.service ), eu esperaria que se eu matasse foo_app de tal maneira que Restart=on-abnormal fosse acionado (por exemplo, killall -9 foo_app ), o systemd deve dar prioridade a Restart=on-abnormal sobre OnFailure=systemd-reboot.service e não iniciar systemd-reboot.service .

No entanto, isso não é o que estou vendo. Assim que eu matar foo_app uma vez, o sistema será reinicializado imediatamente.

Aqui estão alguns trechos relevantes dos documentos:

OnFailure=

A space-separated list of one or more units that are activated when this unit enters the "failed" state. A service unit using Restart= enters the failed state only after the start limits are reached.

Restart=

[snip] Note that service restart is subject to unit start rate limiting configured with StartLimitIntervalSec= and StartLimitBurst=, see systemd.unit(5) for details. A restarted service enters the failed state only after the start limits are reached.

A documentação parece bem clara:

  • Os serviços especificados em OnFailure só devem ser executados quando um serviço inserir o estado " failed "
  • Um serviço só deve inserir o estado " failed " depois que StartLimitIntervalSec e StartLimitBurst forem satisfeitos.

Não é isso que estou vendo.

Para confirmar isso, editei meu arquivo de serviço para o seguinte:

[Unit]
Description=Foo Hardware Monitor  

StartLimitBurst=3
StartLimitIntervalSec=30
StartLimitAction=none

[Service]
ExecStart=/usr/bin/foo_app
Restart=on-abnormal

Removendo OnFailure e definindo StartLimitAction=none , pude ver como o systemd está respondendo a foo_app morrendo. Aqui está um teste em que eu mato repetidamente foo_app com SIGKILL .

[root@device ~]
# systemctl start foo.service
[root@device ~]
# journalctl -f -o cat -u foo.service &
[1] 2107
Started Foo Hardware Monitor.
[root@device ~]
# killall -9 foo_app
foo.service: Main process exited, code=killed, status=9/KILL
foo.service: Unit entered failed state.
foo.service: Failed with result 'signal'
foo.service: Service hold-off time over, scheduling restart.
Stopped foo.
Started foo.

[root@device ~]
# killall -9 foo_app
foo.service: Main process exited, code=killed, status=9/KILL
foo.service: Unit entered failed state.
foo.service: Failed with result 'signal'
foo.service: Service hold-off time over, scheduling restart.
Stopped foo.
Started foo.

[root@device ~]
# killall -9 foo_app
foo.service: Main process exited, code=killed, status=9/KILL
foo.service: Unit entered failed state.
foo.service: Failed with result 'signal'
foo.service: Service hold-off time over, scheduling restart.
Stopped foo.
foo.service: Start request repeated too quickly
Failed to start foo.
foo.service: Unit entered failed state.
foo.service: Failed with result 'start-limit-hit'

Isso faz sentido ou a maior parte. Quando foo_app é eliminado, o systemd reinicia-o até StartLimitBurst ser atingido e, em seguida, desiste. Isto é o que eu quero, exceto com StartLimitAction=reboot .

O que é incomum é que o systemd imprime foo.service: Unit entered failed state. sempre que foo_app é eliminado, mesmo que esteja prestes a ser reiniciado por Restart=on-abnormal . Isso parece contradizer diretamente essas linhas dos documentos citados acima:

A service unit using Restart= enters the failed state only after the start limits are reached.

A restarted service enters the failed state only after the start limits are reached.

Tudo isso me deixou bastante confuso. Eu estou entendendo mal essas opções do systemd? Isso é um bug do systemd? Qualquer ajuda é apreciada.

    
por Matt K 09.02.2018 / 00:50

1 resposta

4

TL; DR - Problema de documentação conhecida, que ainda é um problema pendente para o projeto systemd

Acontece que, desde que você fez essa pergunta, isso foi relatado e identificado como uma discrepância em systemd entre a documentação e o comportamento real. No meu entendimento (e minha leitura da questão do github) sua expectativa e a documentação combinam, então você não está louco.

Atualmente, systemd define o estado como falho após cada tentativa de início, independentemente de o limite de início ter sido atingido. Na edição, o OP escreveu uma divertida história sobre aprender a andar de bicicleta que eu sugiro que você dê uma olhada.

    
por 28.03.2018 / 22:23

Tags