Afin d'effectuer un nettoyage si le service échoue, vous pouvez utiliser ExecStopPost=
, qui est exécuté que le service réussisse ou non.
Dans le code que vous exécutez à ExecStopPost=
, vous pouvez utiliser l'un des $SERVICE_RESULT
, $EXIT_CODE
ou $EXIT_STATUS
pour déterminer la condition de défaillance et agir en conséquence. Consultez la documentation sur ces variables d'environnement pour vérifier celle qui vous convient.
Ensuite, vous pouvez utiliser Restart=on-failure
afin que systemd essaie de redémarrer votre unité en cas d'échec.
En mettant tout cela ensemble, voici à quoi cela ressemblerait. En supposant que run_program
sortira avec le statut 2 chaque fois que les fichiers sont corrompus (j'espère que vous pourrez adapter cela à d'autres scénarios d'échec à partir de la documentation ci-dessus), cela devrait fonctionner :
[Service]
ExecStart=/bin/run_program
ExecStopPost=/bin/sh -c 'if [ "$$EXIT_STATUS" = 2 ]; then rm /file/to/delete; fi'
Restart=on-failure
(REMARQUE :Le double signe dollar $$
est d'échapper à systemd, donc le shell voit $EXIT_STATUS
et accède à cette variable. L'utilisation d'un seul signe dollar fonctionnerait également, mais systemd effectuerait ce remplacement à la place et le shell verrait [ "2" = 2 ]
, qui fonctionne sans doute aussi... Quoi qu'il en soit, vous pouvez contourner la plupart de cela en mettant toute cette logique dans un script shell et en l'appelant par son chemin complet dans ExecStopPost=
, ce serait probablement mieux et vous pourriez aussi facilement ajouter plus de commandes au script, comme enregistrer l'action entreprise pour récupérer de la condition d'erreur.)
J'espère que cela vous donnera suffisamment d'indications pour comprendre comment configurer cela correctement compte tenu de votre situation particulière !
REMARQUE :Vous souhaitez probablement utiliser ExecStopPost=
au lieu de OnFailure=
ici (voir mon autre réponse), mais cela essaie de comprendre pourquoi votre OnFailure=
la configuration ne fonctionne pas.
Le problème avec OnFailure=
ne pas démarrer l'unité peut être parce qu'elle est dans la mauvaise section, elle doit être dans le [Unit]
section et non [Service]
.
Vous pouvez essayer ceci à la place :
# software.service
[Unit]
Description=Software
OnFailure=software-fail.service
[Service]
ExecStart=/bin/run_program
Et :
# software-fail.service
[Unit]
Description=Delete corrupt files
[Service]
ExecStart=/bin/rm /file/to/delete
ExecStop=/bin/systemctl --user start software.service
Je peux le faire fonctionner avec cette configuration.
Mais notez que l'utilisation de OnFailure=
n'est pas idéal ici, car vous ne pouvez pas vraiment dire pourquoi le programme a échoué, et enchaîner un autre démarrage en ExecStop=
en appelant le /bin/systemctl start
directement est assez hacky... La solution utilisant ExecStopPost=
et regarder le statut de sortie est définitivement supérieur.
Si vous définissez OnFailure=
à l'intérieur de [Service]
, systemd (au moins la version 234 de Fedora 27) se plaint avec :
software.service:6: Unknown lvalue 'OnFailure' in section 'Service'
Vous ne savez pas si vous voyez cela dans vos journaux ou non... (Peut-être que cela a été ajouté dans un systemd récent ?) Cela devrait être un indice de ce qui se passe là-bas.