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.