Vorbemerkungen

Vorbemerkungen

Ich habe ein Dotnet-Programm, das innerhalb von Bash in tmux läuft und gelegentlich mit einem Fehlercode ungleich Null fehlschlägt. Ich versuche, eine systemd-Dienstdatei zu verwenden, um mein Dotnet-Programm innerhalb von tmux programmgesteuert zu starten.

Hier ist die Servicedatei:

[Unit] 
Description=dotnet application

[Service] 
Type=forking 
ExecStart=/home/alpine_sour/scripts/rofdl
Restart=always 
User=root

[Install]
WantedBy=multi-user.target

Hier ist das Rofdl-Shell-Skript:

#!/bin/bash 
/usr/bin/tmux kill-session -t "rof" 2> /dev/null || true 
/usr/bin/tmux new -s "rof" -d "cd /home/alpine_sour/rofdl && dotnet run"

Wenn ich den Dienst jetzt starte, wählt systemd die Haupt-PID als tmux-Server, was vermutlich daran liegt, dass es der erste ausgeführte Befehl war. Wenn also mein Programm im tmux-Fenster mit IRGENDEINEM Fehlercode beendet wird UND keine weiteren Fenster vorhanden sind, wird der tmux-Server mit einem Erfolgsfehlercode beendet, was dazu führt, dass systemd nicht neu gestartet wird. Selbst wenn ich Restart=always festlegen würde, würde der tmux-Server nur neu gestartet, wenn mein Programm fehlschlägt UND keine weiteren Fenster vorhanden sind.

  Process: 24980 ExecStart=/home/alpine_sour/scripts/rofdl (code=exited, status=0/SUCCESS)
 Main PID: 24984 (tmux: server)
           ├─24984 /usr/bin/tmux new -s rofdl -d cd /home/alpine_sour/rofdl && dotnet run -- start
           ├─24985 sh -c cd /home/alpine_sour/rofdl && dotnet run -- start
           ├─24987 dotnet run -- start
           └─25026 dotnet exec /home/alpine_sour/rofdl/bin/Debug/netcoreapp2.1/rofdl.dll start

Ich frage mich also, wie ich systemd dazu bringen kann, die niedrigste Ebene des Prozesszweigs zu verfolgen und nicht den Tmux-Server auf höherer Ebene. Ich muss systemd irgendwie anweisen, den untergeordneten Prozess des Tmux-Servers zu verfolgen und nicht den Server selbst, und entsprechend neu zu starten.

Antwort1

Vorbemerkungen

  • Diese Antwort basiert auf Experimenten in Debian 9.
  • Ich gehe davon aus, dass Ihr Dienst ein Systemdienst (in /etc/systemd/system) ist.
  • Was Sie am Ende des Fragentextes gepostet haben, sieht aus wie einAuszugvon systemctl status …. Es steht nichts über cgroups. Diese Antwort setzt vorausKontrollgruppensind beteiligt. Ich denke systemd, sie sind erforderlich, also müssen sie es sein.
  • Der Befehl selbst kann in einer Schleife ausgeführt werden, bis er erfolgreich ist:

    cd /home/alpine_sour/rofdl && while ! dotnet run; do :; done
    

    aber ich verstehe, dass Sie eine systemdLösung wollen.


Probleme

Bitte lesen Sie zuerstWie tmuxfunktioniert. Es ist sehr hilfreich zu verstehen, welcher Prozess wessen Kind ist.

Welche Prozesse gehören zum Service

In Ihrem ursprünglichen Fall wird der Dienst als inaktiv betrachtet (und ggf. zum Neustart bereit), nachdem alle Prozesse aus seiner Kontrollgruppe beendet wurden.

tmuxIhr Skript versucht, die alte Sitzung zu beenden , nicht den alten tmuxServer. Dann startet tmux new(entspricht tmux new-session) entweder ein neuer Server oder verwendet den alten.

  • Wenn das alte verwendet wird, dotnet …sind weder der Server noch Ihr Befehl () ein Nachkomme des Skripts. Diese Prozesse gehören nicht zur mit dem Dienst verknüpften Kontrollgruppe. Nachdem das Skript beendet wurde, systemdwird der Dienst als inaktiv betrachtet.

  • Wenn ein neuer Server gestartet wird, tmuxwerden der Server und der Befehl der mit dem Dienst verknüpften Kontrollgruppe zugewiesen. Dann kann unser Befehl beendet werden, aber wenn sich auf dem Server andere Sitzungen/Fenster (die später erstellt werden) befinden, kann der Server bestehen bleiben und systemdden Dienst als aktiv betrachten.

Wenn es einen Hauptprozess gibt, wird die gesamte Kontrollgruppe beendet, nachdem der Hauptprozess beendet wurde. Bei Type=simpleist der Hauptprozess derjenige, der durch angegeben wird ExecStart=. Bei Type=forkingmüssen Sie PIDFile=eine PID verwenden und auf diese Weise übergeben, um den Hauptprozess anzugeben. Und wenn Sie einen Dienst beenden, systemdwerden alle Prozesse beendet, die zu dem Dienst gehören. Daher ist es wichtig, nur Prozesse in die Kontrollgruppe aufzunehmen, die für den Dienst spezifisch sind. In Ihrem Fall möchten Sie möglicherweise tmuxden Server ausschließen, auch wenn er innerhalb des Dienstes gestartet wird.

Es gibt Tools/Möglichkeiten, Prozesse zwischen Kontrollgruppen zu verschieben. Oder Sie können einen separaten tmuxServer speziell für den Dienst ausführen.

Wer systemdweiß, welcher Exit-Status zu verwenden ist

Restart=on-failurelegt die Abhängigkeit vom Beendigungsstatus des Hauptprozesses fest. Es Type=forkingwird empfohlen, es zu verwenden, PIDFile=damit systemdSie wissen, welcher Beendigungsstatus verwendet werden soll.

systemdDer Beendigungsstatus kann jedoch möglicherweise abgerufen werden, möglicherweise aber auch nicht.

Wer ruft den Exit-Status ab?

Nach dem Beenden eines untergeordneten Elements kann das übergeordnete Element den Beendigungsstatus abrufen (vgl.Zombie-Prozess).

Unabhängig davon, ob der tmuxServer alt oder neu ist, wird Ihr Befehl kein Kind von sein, systemdes sei denn, er wird verwaist. Der Kernel setzt seinen Elternteil auf PID 1 (oder ein anderes) und der neue Elternteil ist der rechte systemd.

Der von Ihnen angegebene Befehl tmux newveranlasst den tmuxServer, eine Shell auszuführen. Anschließend wird die Shell entweder ausgeführt dotnetund wartet auf ihre Beendigung oder execführt eine Shell-Operation aus, dotnetwobei der tmuxServer als übergeordneter Server beibehalten wird. In jedem Fall dotnethat er einen übergeordneten Server, der nicht systemd.

Sie könnten es dotnetwie folgt verwaist machen: nohup dotnet … &und dann die besagte Shell beenden lassen. Sie müssten auch die PID speichern und PIDFile=in der Unit-Konfigurationsdatei verwenden, damit der Dienst weiß, welchen Prozess er überwachen soll. Dann könnte es irgendwie funktionieren.

Um es klar zu sagen: In meinen Tests nohup sleep 300 &wurde es erfolgreich übernommen, und systemdwer konnte dann seinen Beendigungsstatus abrufen (nachdem ich mich um die Cgroups gekümmert hatte).

tmuxAber da Sie in erster Linie verwenden möchten , gehe ich davon aus, dass Ihr Befehl mit dem Terminal interagiert. Alsonohupist hier nicht das richtige Werkzeug. Einen Prozess zu verwaisten, während er mit dem Terminal verbunden bleibt, kann schwierig sein. Sie möchten ihn verwaist machen, können die Shell darin aber nicht tmuxeinfach beenden, da dies ihre Fensterfläche zerstören würde (oder sie in einem toten Zustand belassen würde).

Hinweis : Type=forkingEs basiert auf der Übernahme durch systemd. Der Hauptdienstprozess soll sich verzweigen und beenden. Dann systemdübernimmt er sein Kind. Ein solcher Daemon sollte jedoch nicht mit einem Terminal interagieren.

Ein anderer Ansatz besteht darin, die Shell innerhalb des tmuxServers execausführen zu lassen dotnet. Nach dem Beenden tmuxkennt der Server (als übergeordneter Server) seinen Beendigungsstatus. Unter bestimmten Umständen können wir den Server von einem anderen Skript aus abfragen und den Beendigungsstatus abrufen.

Oder die ausgelöste Shell tmux newspeichert den Status in einer Datei, sodass er von einem anderen Skript abgerufen werden kann.

Da das, was Sie ausführen, mit Sicherheit ExecStart=ein Kind von ist systemd, ist dies der beste Kandidat für „ein anderes Skript“. Es sollte warten, bis es den Beendigungsstatus abrufen kann, und ihn dann als seinen eigenen Beendigungsstatus verwenden, damit er ihn erhält. Beachten Sie, dass der Dienst in diesem Fall systemdsein sollte .Type=simple

Alternativ können Sie auch dotnet …außerhalb von beginnen tmuxund dannreptyrvon innerhalb des tmuxServers. Auf diese Weise kann von Anfang an dotnetein Kind von sein , es können jedoch Probleme auftreten, wenn Sie versuchen, dessen TTY zu stehlen.systemd


Lösungen und Beispiele

reptyrZutmux

Dieses Beispiel führt das Skript in aus tty2. Das Skript bereitet sich vor tmuxund execsendet an . Schließlich versucht dotneteine Shell darin, tty von dem zu stehlen, was jetzt ist .tmuxdotnet

Die Servicedatei:

[Unit]
Description=dotnet application
[email protected]

[Service]
Type=simple
ExecStart=/home/alpine_sour/scripts/rofdl
Restart=on-failure
User=root
StandardInput=tty
TTYPath=/dev/tty2
TTYReset=yes
TTYVHangup=yes

[Install]
WantedBy=multi-user.target

/home/alpine_sour/scripts/rofdl:

#!/bin/sh
tmux="/usr/bin/tmux"

"$tmux" kill-session -t "rof" 2> /dev/null
"$tmux" new-session -s "rof" -d "sleep 5; exec /usr/bin/reptyr $$" || exit 1

cd /home/alpine_sour/rofdl && exec dotnet run

Anmerkungen:

  • Meine Tests mit htopstattdessen dotnet runergaben einen Race Condition ( htopändert die Einstellungen des Terminals, reptyrkann stören; daher sleep 5kein guter Workaround) und Probleme mit der Mausunterstützung.
  • Es ist möglich, den Server aus der mit dem Dienst verknüpften Kontrollgruppe zu entfernen . Das möchten Sie wahrscheinlich tun. Sehen Sie weiter unten, wo im Code tmuxdas steht ./sys/fs/cgroup/systemd/

Ohne tmux?

Die obige Lösung wird /dev/tty2trotzdem verwendet. Wenn Sie tmuxnur ein Steuerterminal bereitstellen müssen, ziehen Sie cd /home/alpine_sour/rofdl && exec dotnet runohne reptyr, ohne in Betracht tmux. Auch ohne das Skript:

ExecStart=/bin/sh -c 'cd /home/alpine_sour/rofdl && exec dotnet run' rofdl

Das ist das Einfachste.

Separater tmuxServer

tmuxermöglicht es Ihnen, mehr als einen Server pro Benutzer auszuführen. Sie müssen -Loder -S(siehe man 1 tmux) einen Socket angeben und dann dabei bleiben. Auf diese Weise kann Ihr Dienst einen exklusiven tmuxServer ausführen. Vorteile:

  • Der Server und alles, was Sie darin ausführen, tmuxgehört standardmäßig zur Kontrollgruppe des Dienstes.
  • Der Dienst kann den Server zerstören, tmuxohne dass das Risiko besteht, dass irgendjemand (oder irgendetwas) anderes seine Sitzungen verliert. Niemand sonst sollte diesen Server verwenden, es sei denn, er möchte den Dienst überwachen/mit ihm interagieren. Wenn ihn jemand für etwas anderes verwendet, ist das sein Problem.

Die Möglichkeit, den Server beliebig zu beenden, tmuxermöglicht es Ihnen, Prozesse, die in ausgeführt werden, zu verwaisten tmux. Betrachten Sie das folgende Beispiel.

Die Servicedatei:

[Unit]
Description=dotnet application

[Service]
Type=forking
ExecStart=/home/alpine_sour/scripts/rofdl
Restart=on-failure
User=root
PIDFile=/var/run/rofdl.service.pid

[Install]
WantedBy=multi-user.target

/home/alpine_sour/scripts/rofdl:

#!/bin/sh
tmux="/usr/bin/tmux"
service="rofdl.service"

"$tmux" -L "$service" kill-server 2> /dev/null
"$tmux" -L "$service" new-session -s "rof" -d '
      trap "" HUP
      ppid="$PPID"
      echo "$$" > '" '/var/run/$service.pid' "'
      cd /home/alpine_sour/rofdl && dotnet run
      status="$?"
   '" '$tmux' -L '$service' kill-server 2> /dev/null "'
      while [ "$ppid" -eq "$(ps -o ppid= -p "$$")" ]; do sleep 2; done
      exit "$status"
  ' || exit 1

Erläuterung:

  1. Das Hauptskript beendet den exklusiven tmuxServer (sofern vorhanden) und startet ihn neu. Nachdem der Server gestartet ist, wird das Skript beendet. Der Dienst bleibt bestehen, da in der Kontrollgruppe noch mindestens ein Prozess übrig ist, nämlich der besagte Server.

  2. Der Server startet eine Shell, um das „innere“ Skript zu verarbeiten. Das Skript beginnt nach 'und -dendet 'vor ||. Es ist vollständig in Anführungszeichen gesetzt, aber die Anführungszeichen ändern sich einige Male von einfachen in doppelte Anführungszeichen und zurück. Dies liegt daran, dass $tmuxund $servicevon der Shell erweitert werden müssen, die das Hauptskript verarbeitet. Andere Variablen (z. B. $status) dürfen erst in der „inneren“ Shell innerhalb erweitert werden tmux. Die folgende Ressource kann hilfreich sein:Parametererweiterung (Variablenerweiterung) und Anführungszeichen in Anführungszeichen.

  3. Die Shell im Inneren tmuxbereitet sich darauf vor, das Signal zu ignorieren HUP.

  4. Die Shell registriert ihre PID in der vom Dienst erwarteten PID-Datei.

  5. Dann wird es ausgeführt dotnetund speichert seinen Beendigungsstatus (streng genommen, wenn cdes fehlschlägt, ist es der Beendigungsstatus von cd).

  6. Die Shell beendet den tmuxServer. Wir könnten dies kill "$PPID"auch mit tun (sieheDas), aber wenn jemand den Server beendet hätte und ein anderer Prozess dessen PID erhalten hätte, würden wir einen falschen Prozess beenden. Die Adressierung tmuxist sicherer. Denn dadurch trapbleibt die Shell erhalten.

  7. Dann wiederholt die Shell die Schleife, bis ihre PPID eine andere ist als die vorherige. Wir können uns nicht auf den Vergleich $ppidmit verlassen $PPID, da letzteres nicht dynamisch ist; wir rufen die aktuelle PPID von ab ps.

  8. Jetzt weiß die Shell, dass sie einen neuen übergeordneten Status hat, es sollte sein systemd. Erst jetzt systemdkann der Beendigungsstatus von der Shell abgerufen werden. Die Shell wird mit dem exakten Beendigungsstatus beendet, der dotnetzuvor abgerufen wurde. Auf diese Weise systemderhält man den Beendigungsstatus, obwohl er dotnetnie ihr untergeordneter Status war.

Abrufen des Beendigungsstatus vom gemeinsamen tmuxServer

Ihr ursprünglicher Ansatz verwendet einen gemeinsamen (Standard-) tmuxServer und manipuliert nur eine Sitzung mit dem Namen rof. Im Allgemeinen können andere Sitzungen vorhanden sein oder entstehen, daher sollte der Dienst niemals den gesamten Server beenden. Es gibt einige Aspekte. Wir sollten:

  • Verhindern Sie systemd, dass der tmuxServer beendet wird, selbst wenn der Server innerhalb des Dienstes gestartet wurde.
  • Betrachten Sie systemdden dotnetProzess als Teil des Dienstes, auch wenn er tmuxnicht innerhalb des Dienstes gestartet wurde.
  • den Beendigungsstatus dotnetirgendwie abrufen.

Die Servicedatei:

[Unit]
Description=dotnet application

[Service]
Type=simple
ExecStart=/home/alpine_sour/scripts/rofdl
Restart=on-failure
User=root

[Install]
WantedBy=multi-user.target

Beachten Sie, dass dies Type=simplejetzt der Fall ist, da das Hauptskript das einzige gesicherte untergeordnete Element ist, von dem wir den Beendigungsstatus abrufen können. Das Skript muss den Beendigungsstatus ermitteln dotnet …und ihn als seinen eigenen melden.

/home/alpine_sour/scripts/rofdl:

#!/bin/sh
tmux="/usr/bin/tmux"
service="rofdl.service"
slice="/sys/fs/cgroup/systemd/system.slice"

"$tmux" kill-session -t "rof" 2> /dev/null
( sh -c 'echo "$PPID"' > "$slice/tasks"
  exec "$tmux" new-session -s "rof" -d "
      '$tmux' set-option -t 'rof' remain-on-exit on "'
      echo "$$" > '" '$slice/$service/tasks' "'
      cd /home/alpine_sour/rofdl && dotnet run
      exit "$?"
    ' || exit 1
)

pane="$("$tmux" display-message -p -t "rof" "#{pane_id}")"

while sleep 2; do
  [ "$("$tmux" display-message -p -t "$pane" "#{pane_dead}")" -eq 0 ] || {
    status="$("$tmux" display-message -p -t "$pane" "#{pane_dead_status}")"
    status="${status:-255}"
    exit "$status"
  }
done

Erläuterung:

  1. Wenn tmux new-sessionein Server erstellt wird (weil es keinen gab), möchten wir ihn von Anfang an in einer anderen Kontrollgruppe haben, um einen Race Condition zu vermeiden, wenn etwas anderes den Server zu verwenden beginnt und wir seine Kontrollgruppe noch nicht geändert haben und systemdder Dienst aus irgendeinem Grund beendet werden soll. Ich habe versucht, es tmux new-sessionmit auszuführen cgexec, aber es ist fehlgeschlagen. Daher ein anderer Ansatz: eine Subshell, die ihre eigene Kontrollgruppe ändert (indem sie in schreibt /sys/fs/cgroup/systemd/system.slice/tasks) und dann execin schreibt tmux new-session.

  2. Die darin enthaltene Shell tmuxbeginnt mit der Aktivierung remain-on-exitder Option für die Sitzung. Nach der Beendigung bleibt der Bereich bestehen und ein anderer Prozess (in unserem Fall das Hauptskript) kann seinen Beendigungsstatus vom tmuxServer abrufen.

  3. In der Zwischenzeit ruft das Hauptskript die eindeutige ID des Bereichs ab, in dem die andere Shell ausgeführt wird. Wenn sich jemand an der Sitzung anmeldet oder neue Bereiche erstellt und mit ihnen spielt, kann das Hauptskript weiterhin den richtigen Bereich finden.

  4. Die darin enthaltene Shell tmuxregistriert ihre PID in der mit dem Dienst verknüpften Kontrollgruppe, indem sie sie in schreibt /sys/fs/cgroup/systemd/system.slice/rofdl.service/tasks.

  5. Die darin enthaltene Shell tmuxführt aus dotnet …. Nach dotnetBeendigung wird die Shell beendet. Der von abgerufene Beendigungsstatus dotnetwird von der Shell an den tmuxServer gemeldet.

  6. Aufgrund von remain-on-exit onbleibt die Scheibe nach dem Verlassen der „inneren“ Schale in einem toten Zustand.

  7. In der Zwischenzeit wird die Haupt-Shell in einer Schleife ausgeführt, bis der Bereich tot ist. Dann fragt sie den tmuxServer nach dem entsprechenden Beendigungsstatus ab und meldet ihn als ihren eigenen. Auf diese Weise systemderhält sie den Beendigungsstatus von dotnet.

Anmerkungen:

  • Wieder gibt esAnführungszeichen in Anführungszeichen.

  • Anstelle von dotnet runkönnte es sein exec dotnet run. Die letzte Form ist nett: dotnetersetzt die innere Shell, sodass es einen Prozess statt zwei gibt. Das Problem ist, wenn dotnetdurch ein Signal beendet wird, das es nicht verarbeiten kann. Es stellt sich heraus, dass #{pane_dead_status}eine leere Zeichenfolge gemeldet wird, wenn der Prozess im Bereich durch ein Signal zwangsweise beendet wird. Die Aufrechterhaltung einer Shell zwischen dotnetund tmuxverhindert dies: Die Shell transformiert Informationen (siehediese Frage) und gibt eine Zahl zurück.

    Einige Shells (Implementierungen?) führen den allerletzten Befehl mit implicit aus exec, was wir nicht wollen. Deshalb habe ich exit "$?"after verwendet dotnet ….

    Wenn die Shell selbst jedoch zwangsweise beendet wird, tritt das Problem mit dem leeren Zustand #{pane_dead_status}erneut auf. Als letzte Möglichkeit wird der status="${status:-255}"leere Zustand in 255(obwohl ich nicht sicher bin, 255ob dies in einem solchen Fall der beste Wert ist) umgewandelt.

  • Es gibt einen Race Condition: Wenn das Hauptskript nach abfragt tmux, #{pane_id}ist es möglicherweise nicht der richtige Bereich. Wenn jemand nach tmux new-sessionund vor in der Sitzung eine Verbindung hergestellt und gespielt hat tmux display-message, erhalten wir möglicherweise einen falschen Bereich. Das Zeitfenster ist klein, aber trotzdem ist dies nicht so elegant, wie ich es wollte.

    Wenn Sie wie möglich auf der Konsole tmux new-sessiondrucken könnten , sollte es kein Problem geben. Damit können Sie es innerhalb der Sitzung anzeigen. Es gibt keine Unterstützung für .#{pane_id}tmux display-message -p-PF-p

  • Möglicherweise benötigen Sie eine Logik für den Fall, dass der tmuxServer abgestürzt ist.

Abrufen des Beendigungsstatus über eine Datei

Das obige Beispiel kann geändert werden, ist also nicht remain-on-exit onerforderlich #{pane_id}(Race Condition vermieden, zumindest der beschriebene).

Die Servicedatei aus dem vorherigen Beispiel bleibt bestehen.

/home/alpine_sour/scripts/rofdl:

#!/bin/sh
tmux="/usr/bin/tmux"
service="rofdl.service"
slice="/sys/fs/cgroup/systemd/system.slice"
statf="/var/run/$service.status"

rm "$statf" 2>/dev/null

"$tmux" kill-session -t "rof" 2> /dev/null
( sh -c 'echo "$PPID"' > "$slice/tasks"
  exec "$tmux" new-session -s "rof" -d '
      echo "$$" > '" '$slice/$service/tasks' "'
      cd /home/alpine_sour/rofdl && dotnet run
      echo "$?" > '" '$statf.tmp'
      mv '$statf.tmp' '$statf'
    " || exit 1
)

while sleep 2; do
  status="$(cat "$statf" 2>/dev/null)" && exit "$status"
done

Der Mechanismus ist ziemlich unkompliziert: Die Hauptshell entfernt die alte Statusdatei (sofern vorhanden), löst sie aus tmuxund führt eine Schleife aus, bis die Datei wieder erscheint. Die „innere“ Shell schreibt den Beendigungsstatus in dotnetdie Datei, wenn sie bereit ist.

Anmerkungen:

  • Was passiert, wenn die innere Shell beendet wird? Was passiert, wenn die Datei nicht erstellt werden kann? Es kann relativ leicht passieren, dass das Hauptskript die Schleife nicht verlassen kann.
  • Es ist eine gute Praxis, in eine temporäre Datei zu schreiben und sie dann umzubenennen. Wenn wir das täten echo "$?" > "$statf", würde die Datei leer erstellt und dann beschrieben. Dies könnte zu einer Situation führen, in der das Hauptskript eine leere Zeichenfolge als Status liest. Im Allgemeinen könnte der Empfänger unvollständige Daten erhalten: Lesen bis EOF, während der Sender mitten im Schreiben ist und die Datei noch wächst. Durch das Umbenennen wird sofort die richtige Datei mit dem richtigen Inhalt angezeigt.

Abschließende Anmerkungen

  • Wenn Sie nicht darauf verzichten können tmux, erscheint die Lösung mit einem separaten tmuxServer am robustesten.
  • Das ist, was dieDokumentationsagt über Restart=:

    In diesem Kontext bedeutet ein sauberer Ausgang einen Ausgangcode von 0oder eines der Signale SIGHUP, SIGINT, SIGTERModer SIGPIPE, und […]

    Hinweis: $?In einer Shell ist es nur eine Zahl. Nochmal:dieser Link. Wenn Ihr dotnetSystem aufgrund eines Signals beendet wird und der Neustart von einem (un-)sauberen Beenden abhängt, können sich die Lösungen, bei denen der systemdBeendigungscode direkt abgerufen wird, dotnetanders verhalten als Lösungen, bei denen der systemdBeendigungsstatus von einer zwischengeschalteten Shell abgerufen wird. Recherchieren Sie SuccessExitStatus=, es kann hilfreich sein.

Antwort2

Möglicherweise können Sie RestartForceExitStatus=die Servicedatei verwenden

Nimmt eine Liste von Beendigungsstatusdefinitionen an, die, wenn sie vom Hauptdienstprozess zurückgegeben werden, automatische Neustarts des Dienstes erzwingen, unabhängig von der mit Restart= konfigurierten Neustarteinstellung. Das Argumentformat ist ähnlich wie RestartPreventExitStatus=.

https://www.freedesktop.org/software/systemd/man/systemd.service.html

verwandte Informationen