Para realizar una limpieza si el servicio falla, puede usar ExecStopPost=
, que se ejecuta ya sea que el servicio tenga éxito o no.
En el código que ejecutas en ExecStopPost=
, puedes usar uno de $SERVICE_RESULT
, $EXIT_CODE
o $EXIT_STATUS
para determinar la condición de falla y actuar en consecuencia. Consulte la documentación sobre esas variables de entorno para comprobar cuál es la adecuada para usted.
Entonces puedes usar Restart=on-failure
para que systemd intente reiniciar su unidad cuando falle.
Poniéndolo todo junto, así es como se vería. Suponiendo que run_program
saldrá con el estado 2 cada vez que los archivos estén dañados (con suerte, puede adaptar esto a otros escenarios de falla de la documentación anterior), esto debería funcionar:
[Service]
ExecStart=/bin/run_program
ExecStopPost=/bin/sh -c 'if [ "$$EXIT_STATUS" = 2 ]; then rm /file/to/delete; fi'
Restart=on-failure
(NOTA :El doble signo de dólar $$
es escapar de esto a systemd, por lo que el shell ve $EXIT_STATUS
y accede a esa variable. Usar un solo signo de dólar también funcionaría, pero luego systemd haría ese reemplazo y el shell vería [ "2" = 2 ]
, que podría decirse que también funciona... De todos modos, puede omitir la mayor parte de eso colocando toda esta lógica en un script de shell y llamándolo por su ruta completa en ExecStopPost=
, probablemente sería mejor y también podría agregar fácilmente más comandos a la secuencia de comandos, como registrar la acción realizada para recuperarse de la condición de error).
¡Esperemos que esto le brinde suficientes consejos para descubrir cómo configurar esto correctamente dada su situación particular!
NOTA :Probablemente quieras usar ExecStopPost=
en lugar de OnFailure=
aquí (ver mi otra respuesta), pero esto está tratando de abordar por qué su OnFailure=
la configuración no funciona.
El problema con OnFailure=
no iniciar la unidad puede deberse a que está en la sección incorrecta, debe estar en el [Unit]
sección y no [Service]
.
Puedes probar esto en su lugar:
# software.service
[Unit]
Description=Software
OnFailure=software-fail.service
[Service]
ExecStart=/bin/run_program
Y:
# software-fail.service
[Unit]
Description=Delete corrupt files
[Service]
ExecStart=/bin/rm /file/to/delete
ExecStop=/bin/systemctl --user start software.service
Puedo hacer que funcione con esta configuración.
Pero tenga en cuenta que usar OnFailure=
no es lo ideal aquí, ya que realmente no se puede saber por qué falló el programa y encadenar otro inicio en ExecStop=
llamando al /bin/systemctl start
directamente es bastante raro... La solución usando ExecStopPost=
y mirar el estado de salida es definitivamente superior.
Si define OnFailure=
dentro de [Service]
, systemd (al menos la versión 234 de Fedora 27) se queja con:
software.service:6: Unknown lvalue 'OnFailure' in section 'Service'
No estoy seguro de si está viendo eso en sus registros o no... (¿Quizás esto se agregó en systemd reciente?) Eso debería ser una pista de lo que está sucediendo allí.