Sinnvolle Fehlerbehandlung bei Hintergrundprogrammen ohne Nutzereingaben

  • VB.NET

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von petaod.

    Sinnvolle Fehlerbehandlung bei Hintergrundprogrammen ohne Nutzereingaben

    Hallöchen Zusammen,

    immer wieder liest und hört man von Try Catch Blöcken. Die einen sind dafür die anderen dagegen.

    Ich stehe jetzt vor einem Problem bei dem ich nicht genau weiß, was die sinnvollste Lösung dafür ist.

    Ich habe einen Windows-Dienst geschrieben, der einen Ordner überwacht. Wenn hier eine neue Datei reinflattert wird eine andere Anwendung mit Parametern gestartet, die dann eben genau diese Datei verarbeitet.

    Soweit so gut..

    Die eigentliche Anwendung (nicht der Windows-Dienst) bearbeitet also die Dateien. Hier soll nun jede Erfolgreich verarbeitete Datei in einen Ordner "Erledigt" verschoben werden.
    Jede Datei die aufgrund von irgendeinem Fehler (egal welcher Art) nicht korrekt bearbeitet werden kann, soll in einen Ordner "Fehler" verschoben werden. Zusätzlich wird hier dann eine Email versendet die den Fehler + Dateinamen beinhaltet um
    diese im nachhinein nochmal Prüfen zu können.

    Das Verschieben der Dateien oder das Senden einer Mail ist hier nicht das Problem, sondern wie man diese Fehler am besten abfängt?

    Am besten wäre natürlich soetwas wie:

    Verarbeite Datei "XY" -> Wenn erfolgreich dann Verschieben in Ordner "Erledigt"
    Wenn nicht erfolgreich (durch egal welchen Fehler) dann "Abbruch" -> Mail Senden -> Verschieben in "Fehler" ->Programm beenden um die nächste Datei zu bearbeiten.

    Ein Fehler soll ja nicht dazu führen, dass gar nichts mehr abgearbeitet wird, sondern nur diese eine Datei eben nicht.

    Aktuell habe ich das über Try Catch erledigt, dass sieht dann ungefähr so aus:

    VB.NET-Quellcode

    1. ​Try
    2. ExecuteParams() 'Aufruf von der eigentlichen Prozedur um die Datei zu bearbeiten.
    3. movefile("Erledigt") 'Funktion um Dateien zu verschieben
    4. Catch ex As Exception
    5. Protokollspeichern("Prot", "Fehler bei: " & aktuelleDatei & " // " & ex.ToString) 'Hier wird nur ein Protokoll geschrieben
    6. ErrorMailSend("Fehler bei: " & aktuelleDatei & " // " & ex.ToString) 'Hier wird die Email gesendet.
    7. movefile("Error") 'Verschieben in "Error"
    8. Application.Exit()
    9. End Try



    Leider ist es nur so, dass die Datei trotzdem in den Ordner "Erledigt" verschoben wird obwohl ein Fehler aufgetreten ist.

    Eventuell habe ich hier dass try catch auch noch nicht richtig verstanden aber eventuell ist try catch auch der Falsche Ansatz dafür?

    Was sagt Ihr dazu? Wie wäre eure Vorgehensweise? ISt try catch hier sinnvoll nur von mir falsch benutzt oder gibt es bessere Methoden?

    Vielen Dank schonmal vorab.

    Gruß
    Wie Du bestimmt schon weißt: Try/Catch ist ein heißes Eisen. Zusammenfassend gesagt: Blindes und Alles-Catchen ist nonsens, gezieltes Catchen sinnvoll.
    Es stellt sich die Frage: Wird denn eine Ex geworfen, wenn ein Fehler auftritt? Ist der Fehler dann überhaupt eine Visual-Studio-interne Exception? Oder gibt es "nur" einen Verarbeitungsfehler in Deinen Prozeduren? Denn das suggeriert Dein Satz

    Holistiker schrieb:

    Jede Datei die aufgrund von irgendeinem Fehler (egal welcher Art) nicht korrekt bearbeitet werden kann
    Dann müsste die Verarbeitungsprozedur auch aktiv eine Exception werfen, damit sie von Catch abgefangen und verarbeitet werden kann. Das findest Du konkret raus, indem Du bei Dir Try-Catch erstmal deaktivierst und einen Fehler provozierst. Kommt eine Ex, dann gib deren Typ in Zeile#7 auch konkret an. Sonst läufst Du Gefahr, dass auch bei wirklich unerwarteten Exceptions was verschoben wird, obwohl dann was ganz anderes geschehen sollte. Und wenn Du schon selber dann in Deiner Verarbeitungsprozedur eine Ex werfen solltest, dann nicht vom generellen Exceptiontyp, sondern eine konkretere. Notfalls ApplicationException. Aber da gibt's bestimmt noch passendere/spezifischere vorgefertigte. Sollte alles nicht so richtig passen, mach Dir ne eigene Exception.
    Generell zu Deiner Frage: Auf den ersten Blick ist das Abfangen per Catch in Deinem Beispiel anscheinend sinnvoll.

    btw: Application.Exit? Wenn eine Fehler auftritt, soll gleich das ganze Programm beendet werden? Wenn ja, dann ist es meistens sauberer Form.Close zu benutzen - falls es eine WinForms-Anwendung ist.

    ##########

    Achso: Für den Fall, dass Dein Verarbeitungsprogramm auf einen Fehler stößt und dann einen Fehler OHNE Exception registriert, einfach weil eine Weiterverarbeitungsvoraussetzung nicht zutrifft, sollte Deine Funktion einfach einen entsprechenden Return-Value haben/zurückgeben statt eine Exception zu werfen. Dann erspart man sich das performancelastige Exception-Catchen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „VaporiZed“ ()

    @Holistiker Ich würde den Dienst zunächst nicht als Dienst, sondern als GUI-Programm laufen lassen, wo Du Dir alle Exceptions in einem Log anzeigen lassen kannst.
    Und dann legst Du fest, wie Du auf welche Exceptions reagieren solltest.
    Dafür ist es sinnvoll, Fehler / Exceptions zu provozieren, um deren programminternen Kontext untersuchen zu können.
    Wenn dann alles läuft, machst Du da wieder einen Dienst draus.
    Aber:
    Wieso übernimmt das Verschieben in die Ordner nicht das verarbeitende Programm selbst?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Holistiker schrieb:

    immer wieder liest und hört man von Try Catch Blöcken. Die einen sind dafür die anderen dagegen.
    Hmm - dagegen?
    Ich kenne niemanden, der in jedem Fall gegen TryCatches ist.

    Wenn man weiss, was man tut, eine unschätzbare Hilfe.
    Andernfalls aber das Gegenteil.

    Und - ja - ein Dienst soll wohl meist nur in extremen Ausnahmefällen abstürzen dürfen. Da muss man dann sehr sorgfältig implementieren - und noch viel sorgfältiger testen - aber ist machbar.

    ErfinderDesRades schrieb:

    und noch viel sorgfältiger testen
    Jou.
    @VaporiZed Und dazu ist es sehr sinnvoll, diesen Dienst zunächst parallel als GUI-Programm zu implementieren und so zu stressen und zu testen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    RodFromGermany schrieb:

    zunächst parallel als GUI-Programm zu implementieren

    @Holistiker:
    Üblicherweise handhabe ich das so, dass ich eine Solution mit drei Projekten mache.
    - Eine DLL, indem der relevante Code abläuft.
    - Eine GUI für den Test, mit Buttons für Start und Stop und die entsprechenden Routinen in der DLL aufruft.
    - Der Service, der nur aus dem Rahmen besteht und bei Start und Stop dasselbe macht wie die GUI-Buttons.
    So lässt sich auch ein Service ganz einfach debuggen.

    Achte darauf, dass die Start- und Stop-Routinen releativ zügig zu Ende kommen (du hast nur 30 s Zeit).
    Erzeuge in der Startroutine einen eigenen Thread, Task oder Timer, in dem die eigentliche Aufgabe erledigt wird.

    Falls du in der DLL unterscheiden willst, ob du als GUI oder als Service läufst (z.B. für Interaktion mit dem Bildschirm) kannst du das an der Property Environment.UserInteractive erkennen.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --