Ich habe einige Monate damit rumgemacht, dass das Konglomerat Telegraf/Prometheus/Grafana von ziemlich starken Abhängigkeiten bei der Startreihenfolge der beteiligten Systeme geplagt ist. Meine Server rebooten alle einmal pro Woche automatisch innerhalb eines gewissen Zeitfensters und seit Grafana musste ich so alle 2-3 Wochen manuell eingreifen und Services neustarten, da insbesondere Telegraf davon ausgeht, dass Schnittstellen, auf die es selbst zugreift, beim eigenen Start erreichbar sein müssen. (Siehe auch: Fallacies of distributed computing.)
Die Frage war also, wie sieht die einfachste Lösung aus, um einen gegebenen Service 60 Minuten nach seinem Start noch einmal automatisch durchzustarten (mit sporadischen Lücken in den Daten kann ich am frühen Sonntagmorgen leben).
Timer und dedizierte Service-Units zu verteilen schien mir zu aufwändig, und ich habe unangenehm lange gegrübelt, wie die simpelste Lösung aussehen könnte, die einfach per systemctl edit foo.service
(oder per anderweitig verteiltem systemd drop-in, ymmv) in die betreffende Unit eingebracht werden kann.
Angekommen bin ich schließlich bei dieser Bandwurmzeile:
# /etc/systemd/system/telegraf.service.d/override.conf
[Service]
ExecStartPost=-+sh -c 'systemctl --quiet is-active %N-restart || systemd-run --unit=%N-restart --on-active=1h systemctl restart %N'
Von rechts nach links:
systemd-run
instanziiert einen transienten timer und service, der in einer Stundesystemctl restart
ausführen wird.%N
wird dabei durch den Namen der übergeordneten Unit (hier also: telegraf) ersetzt.- Der Name des transienten timer und service wird über die Option
--unit
vorgegeben um im vorherigen Schritt (eins weiter links) vorhersagbar zu sein. systemd-run
wird nur dann ausgeführt, wenn nicht bereits eine Unit aktiv ist, die den vorgegebenen Namen hat, den die transiente Unit bekommen würde, wenn sie noch auszuführen wäre.- Das ganze ist als Shell-Aufruf gewrappt, um den
||
– Operator zu haben. ExecStartPost=+
führt als root aus, obwohl die übergeordnete Unit ihre Befehle unprivilegiert ausführt.ExecStartPost=-
ignoriert den Fehler aus dem Shell-Einzeiler, wenn die Unit bereits aktiv war. Es könnte ersatzweise auch; true
ans Ende des Einzeilers geschrieben werden.