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:
- Quando o serviço,
foo.service , é iniciado, ele inicia um aplicativo, foo_app .
-
foo_app monitora o componente de hardware, executando continuamente.
- 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.
- Se
foo_app falhar, o systemd deverá reiniciar foo_app .
- 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.