Ausnahmebehandlung in einem Programm, das rund um die Uhr ausgeführt werden muss

14

Ich habe gelesen, dass wir nur Ausnahmen abfangen sollten, die behandelt werden können, was das Abfangen der Basisausnahmeklasse (in diesem Fall C #) (zusätzlich zu anderen Gründen) zu einer schlechten Idee macht. Ich bin derzeit Teil eines Projekts, in dem ich bisher noch nichts anderes als die Basisausnahme zu sehen habe. Ich erwähnte, dass dies als schlechte Praxis angesehen wird, aber die Antwort lautete: "Dieser Dienst muss rund um die Uhr ausgeführt werden, so ist es also."

Da ich keine gute Antwort darauf hatte, wie Ausnahmen in einem Programm, das rund um die Uhr ausgeführt werden muss, richtig gehandhabt werden, bin ich jetzt hier. Ich habe keine Informationen / Vorschläge zum Umgang mit Ausnahmebehandlungen in "kritischen" Programmen / Diensten gefunden, die rund um die Uhr ausgeführt werden müssen (und in diesem Fall glaube ich, dass es in Ordnung sein kann, wenn der Dienst eine Minute lang nicht verfügbar ist oder zwei, also nicht einmal kritisch). Ich verstehe, es hängt von der genauen Art des Programms ab. Die Anforderungen an ein Programm, das lebensbedrohliche Probleme verursachen kann, sind ganz anders als bei einem Protokollscanner für ein Online-Spiel.

Zwei Beispiele:

1: Ein Type-Ahead-Service für Kunden der britischen Eisenbahnen, der bei der Online-Suche nach Bahnhöfen eingesetzt wird.

2: Ein Programm, das die Eisenbahnweichen für die oben genannten Eisenbahnen automatisch auf der Grundlage von Echtzeitinformationen steuert, die von verschiedenen Sensoren in den Gleisen, Zügen usw. bereitgestellt werden.

Das erste Programm würde wahrscheinlich kein größeres Problem verursachen, wenn es für ein oder zwei Minuten ausfällt, wobei das letztere zu menschlichen Opfern führen könnte. Vorschläge, wie man mit jedem umgeht? Hinweis darauf, wo ich weitere Informationen und Gedanken zu diesem Thema finden kann?

user1323245
quelle
2
Das Abwickeln des Stacks während der Ausnahmebehandlung in einer Echtzeit-App (sic!) Kann einen Zug ruinieren.
Deer Hunter
4
@DeerHunter Falsche Codierung ohne Ausnahmen, kann das gleiche Ergebnis haben.
BЈовић
9
Okay, also du catch Exception. Das bedeutet nicht, dass Ihr Programm funktioniert , es bedeutet, dass bei Fehlern der Anwendungsstatus beschädigt wird, während die Ausführung fortgesetzt wird. Dies ist ein weitaus gefährlicherer Ort. Ein abgestürztes Programm kann katastrophal sein, aber ein Programm, das sich in einem ungültigen Zustand befindet, aber noch Aktionen ausführt, kann aktiv katastrophal sein.
Phoshi
1
Wenn die Anwendung rund um die Uhr ausgeführt werden muss, gibt es irgendwo eine Endlosschleife. Diese Endlosschleife sollte besser um ein Konstrukt gewickelt werden, das alle nicht behandelten Ausnahmen abfängt. Ist dies nicht der Fall, wird eine nicht behandelte Ausnahme auf den bereits vorhandenen Catch-All-Handler angewendet, der sich außerhalb von main befindet, und auf kaboom! Die 24/7-Anwendung wird beendet.
David Hammen

Antworten:

7

Bestimmte Sprachfunktionen mögen

  • Speicherbereinigung
  • Ausnahmesysteme
  • Lazy Evaluation

sind in einem Echtzeitsystem im Allgemeinen nicht nützlich. Man sollte wahrscheinlich eine Sprache ohne diese Funktionen wählen und versuchen, bestimmte Eigenschaften wie die maximale Speichernutzung oder die maximale Antwortzeit nachzuweisen.


Wenn ein Programm kontinuierlich ausgeführt werden muss, aber kurze und nicht globale Fehler akzeptabel sind, können wir eine Erlang-ähnliche Strategie anwenden. Erlang ist eine parallele, funktionale Programmiersprache. In der Regel besteht ein in Erlang geschriebenes Programm aus mehreren Worker-Prozessen, die miteinander kommunizieren können (Akteurmodell). Wenn ein Arbeitsthread auf eine Ausnahme stößt, wird er neu gestartet. Während dies eine kurze Ausfallzeit bedeutet, können die anderen Akteure wie gewohnt weitermachen.

Um dies zusammenzufassen: In einem robusten Programm sind verschiedene Teile voneinander isoliert und können unabhängig voneinander neu gestartet oder skaliert werden.

Im Grunde brauchen wir einen Code, der dem folgenden entspricht:

while (true) {
  try {
    DoWork();
  }
  catch (Exception e) {
    log(e);
  }
}

plus eine Möglichkeit, die Schleife zu beenden. Eine solche Schleife würde dann jeden Worker-Thread antreiben.


Ein Problem beim Ignorieren von Fehlern über ein Catch-All besteht darin, dass Invarianten Ihres Programms möglicherweise durch die Fehlerursache verletzt wurden und nachfolgende Vorgänge möglicherweise unbrauchbar sind. Eine gute Lösung besteht darin, keine Daten zwischen unabhängigen Arbeitnehmern auszutauschen. Wenn Sie einen Worker neu starten, werden alle erforderlichen Invarianten neu erstellt. Dies bedeutet, dass sie unterschiedlich kommunizieren müssen, z. B. durch Nachrichtensendungen. Der Staat eines Schauspielers darf nicht Teil der Invarianten anderer Akteure sein.

Ein weiteres Problem beim Abfangen zu vieler Ausnahmen besteht darin, dass nicht alle Ausnahmen durch einen Neustart behoben werden können, selbst wenn solche Vorsichtsmaßnahmen getroffen werden. Ansonsten harte Probleme wie der Speicher zur Neige kann durch einen Neustart behandelt werden. Ein Neustart hilft Ihnen jedoch nicht, die Internetverbindung wiederherzustellen, wenn ein physisches Kabel herausgezogen wurde.

amon
quelle
1
Ja, aber genau in der Situation, in der ein "physisches Kabel herausgezogen" wurde, soll sich das Ausnahmeprotokoll nur füllen, bis jemand das Kabel wieder einführt. Dann funktioniert es wieder, ohne dass die Anwendung manuell neu gestartet werden muss.
Mark Hurd
2

Um Ihre Frage zu beantworten, muss man verstehen, was Ausnahmen sind und wie sie funktionieren.

Ausnahmen werden normalerweise ausgelöst, wenn solche Fehler auftreten, bei denen die Unterstützung des Benutzers erforderlich ist. In solchen Fällen spielt es keine Rolle, wie lange es dauert, den Stapel abzuwickeln und die Ausnahme zu behandeln.

Ohne catch-Handler stoppt das Programm die Ausführung. Abhängig von Ihrem Setup und Ihren Anforderungen kann dies akzeptabel sein.

In Ihren speziellen Fällen:

  1. Wenn die Abfrage nicht ausgeführt werden kann (z. B. falscher Städtename), informieren Sie den Benutzer über den Fehler und bitten Sie ihn zu beheben.
  2. Wenn Sie keine Informationen von einem kritischen Sensor erhalten, ist es nicht sinnvoll, fortzufahren, ohne den Bediener zu bitten, das Problem zu beheben.

Das bedeutet, dass es in beiden Fällen sinnvoll sein kann, Ausnahmen zu verwenden, wobei in einem RT-Programm vorsichtiger darauf zu achten ist, dass nur schwerwiegende Probleme angezeigt werden, bei denen die Ausführung nicht fortgesetzt werden kann.

BЈовић
quelle
1

Ich habe bisher noch nichts anderes gesehen, als dass die Basisausnahme gefasst wurde.

Es hört sich so an, als gäbe es hier ein Problem, da Ausnahmen nicht angemessen behandelt werden. Durch das Abfangen von Ausnahmen an der richtigen Stelle und das Ergreifen geeigneter Maßnahmen (abhängig von der Art der Ausnahme) wird der Dienst wesentlich zuverlässiger ausgeführt.

Wenn der Service fortgesetzt werden muss, ist es vermutlich wichtig, dass er wie vorgesehen funktioniert. Wenn in Ihrem Beispiel ein Programm, das Eisenbahnweichen steuert, eine Ausnahme auslöst, kann dies auf ein Problem bei der Kommunikation mit sicherheitsrelevanten Sensoren hinweisen. Wenn Sie die Basisausnahme abfangen und fortfahren, wird der Dienst möglicherweise ausgeführt, funktioniert jedoch möglicherweise nicht wie beabsichtigt, was zu einer Katastrophe führt.

Wenn Sie alternativ die Ausnahme abfangen, die bei einem Kommunikationsfehler mit dem Sensor ausgelöst wurde, und diese entsprechend behandeln (dh die Züge in dem betroffenen Bereich anhalten), läuft Ihr Dienst und Sie haben niemanden getötet.

Wenn ich die Frage verstehe, würde ich vorschlagen, dass Sie in der ersten Instanz besser eine spezifischere Ausnahmebehandlung hinzufügen, als die Basis-Ausnahmetyp-Handler zu entfernen.

Matt
quelle
0

Zu Punkt 2: Verwenden Sie kein C #. Es ist keine Echtzeitsprache und Sie werden verletzt, wenn Sie versuchen, sie als solche zu verwenden.

Zu Punkt 1: Sie könnten den Lang-Weg gehen: Lassen Sie es abstürzen, und starten Sie es neu

miniBill
quelle
Meine C # -Nutzung und Kenntnisse liegen nicht bei Punkt 2 (Echtzeit-Spurumschaltung). Ich bin gespannt, warum C # für eine solche Aufgabe so ungeeignet ist.
Michael O'Neill
1
Meistens: Der Garbage Collector macht das Programmverhalten zeitlich unvorhersehbar. Außerdem ist die Laufzeit zu komplex und in diesen Kontexten sind einfache Dinge vorhersehbarer
miniBill
0

Ausschlussklausel: Dies sind nur Gedanken, ich habe nicht die Erfahrung.

Ich würde mir vorstellen, dass ein Programm, das die Anforderungen des zweiten Beispiels erfüllt, extrem modular sein sollte . Folglich können Module neu gestartet werden, ohne das System zu destabilisieren.

Zum Beispiel sollte ein Objekt, das keine Zusicherung für den internen Zustand hat, zerstört und neu erstellt werden können, wobei alle seine Verbraucher und Lieferanten benachrichtigt werden. Genauer gesagt, wenn das Programm die Weichen der Eisenbahn steuert und eine Bestätigung in der Entscheidungsschleife nicht besteht, kann es dennoch ein Notfallmodul ausführen, das alle beteiligten Züge anhält und auf die Neuinitialisierung des Hauptentscheidungsmoduls wartet.

Realistischer würde man Redundanz einführen - Duplizieren der Hardware und Software. Eine Instanz ist mit dem gesteuerten System verbunden und die andere läuft frei. Wenn ein Fehler erkannt wird, werden die Systeme umgeschaltet.

Ein Beispiel sind zwei Prozesse auf demselben Computer, die sich gegenseitig überwachen. Wenn einer beendet wird, wird er vom anderen erneut erzeugt und die übergeordnete PID wird von sich selbst getrennt.

Vorac
quelle