OnAutoItExit - Flexibel zum Abfangen von Fehlern nutzbar?!

  • Hey Leute,

    ich habe mich gefragt, ob man OnAutoItExitRegister() nutzen kann, um flexibel Fehler "abzufangen"?
    Ich stelle mir vor, dass man damit einfach sein Skript noch mal starten kann, wenn es z.B. ein Array-Fehler gab. Wenn man also ein Array erstellt, es nutzt/nutzen will, es aber durch irgendeine Begebenheit nicht erstellt wurde.
    Klar kann man das mit "If IsArray()" abfangen, allerdings ist das viel Code und nicht immer will man nur die eine Funktion dann "auslassen", weil der nachfolgende Rest, der vllt. in ganz anderen Funktionen sind, auch davon abhängt. (Das kann ja so verschachtelt sein, dass es schwer ist, das alles dann zu verbinden.)

    Ich habe mal getestet, wie die Funktion auf falsche Arrays reagiert... Es führt die Funktion aus und beendet dann durch den Fehler.
    Frage: So stapeln sich durch die Rekursion die Fehler-Abbrüche, wenn das öfter vor kommt. Ist das ein starkes Problem oder nur, wenn das wirklich VIEL vor kommt?

    Hier mein Test:

    Spoiler anzeigen
    [autoit]

    OnAutoItExitRegister("MyTestFunc")

    [/autoit] [autoit][/autoit] [autoit]

    Dim $a[3]

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    Sleep(2000)
    MsgBox(4096, "", $a[4])
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func MyTestFunc()
    MsgBox(4096, "", @exitCode)
    EndFunc ;==>MyTestFunc

    [/autoit]

    Damit das keine "Endlosschleife" wird, die auch der User nicht beenden kann, kann man ja die GUI mit einer eigenen Exit-Funktion verbinden und OnAutoItExitUnRegister() nutzen, bevor man beendet.

    Ist das logisch? Übersehe ich etwas? Gibt es bessere Lösungen?


    LG
    Aca

  • Also mir ist der Sinn hinter dem Ganzen noch nicht ganz klar. Wenn du ein Array mit einem falschen Index ansprichst, hast du einen Fehler in deinem Programmcode und da bringt es nichts wenn du das Programm automatisch neustartest. Der Fehler wird sich nicht wegzaubern. Und aus welchem Grund sollte ein Array nicht erstellt werden? Habe ich noch nie gesehen und sollte eigentlich auch nicht passieren. Wenn es doch passiert, müsste es ein Fehler in AutoIt selber sein. Du könntest dir höchstens eine Debug-Nachricht anzeigen lassen, aber das macht AutoIt ja schon von alleine. Sollte es aber darum gehen, dass du überprüfen willst ob eine Funktion wirklich ein Array zurückgibt oder ob ein Fehler aufgetreten ist, dann benutze IsArray und @error. Es macht ja auch keinen Sinn gleich das ganze Programm neuzustarten weil eine Funktion einen Fehler zurückgibt. Führe entweder die Funktion noch mal aus oder beende das Programm gleich ganz, denn dann hast du ja sehr wahrscheinlich irgendwo einen Fehler.

    Gruss Shadowigor

  • Naja, der Sinn ist, dass Werte sich ändern.
    Zum Beispiel: StringRegExp
    Es erstellt nur ein Array, wenn das Pattern passt. Wenn nun aus IRGENDEINEM Grund das Pattern mal nicht passt, obwohl es passen sollte, soll das Programm nicht gleich abbrechen, sondern sich neu starten und dann gucken, ob alle Voraussetzungen richtig sind und die "Fehler-Funktion" einfach (eventuell später, je nach Ergebnis der Prüfung) später noch mal ausführen.

    Mir ist einfach wichtig, dass sich ein Programm nicht beendet, wenn es einen temporären Fehler in der Datenbasis gibt, sondern wieder in die Hauptschleife zurückkehrt. GUI und Betrieb sollen also erhalten bleiben, wenn StringRegExp mal einen Fehler wirft.
    Und wenn man Funktionen sehr abstrakt macht und dementsprechend verschachtelt, reicht ein "If @error Then Return" oder "If IsArray Then ......" nicht aus und macht den Code unnötig komplizierter und bläht ihn in meinen Augen auf.

    "Führe die Funktion noch mal aus" -> Dann müsste man aber jeder Funktion die Überprüfung mitgeben, ob die Datenbasis grade verfügbar/korrekt ist.

    Beispiel: Vertriebssoftware mit GoogleMaps - läuft über die GoogleAPI
    Google ist grade 30 Sekunden nicht verfügbar oder das Internet wird neu gestartet (24 Stunden - Reconnect) -> Programm beendet sich

    Das ist kein Problem, wenn man davor sitzt, aber ich spiele grade auch mit Fernsteuerung via Handy rum und möchte einfach nicht, dass ein Programm wegen solcher Fehler (die selten, aber auf jeden Fall!) auftreten, beendet wird!

    Ist dir der Sinn nun klarer geworden?^^
    (und ja, wenn man Fernsteuerung übers Handy will, sollte man nicht AutoIt nehmen, sondern Hochsprachen, die man auch auf dem Handy nutzen kann Java -> Android & Co... Aber ich mag AutoIt und möchte halt in die Richtung ausprobieren, was möglich ist.)

    LG
    Aca

    • Offizieller Beitrag

    Dein Ansinnen ist schon klar. Aber genau dazu verwendet man doch nach JEDEM möglichen Fehlerquell eine Fehlerbehandlung. :huh:
    In einem großen Programm hast du durchaus 30-40% Error-Handling. Das ist völlig normal. Und es macht wirklich keinen Sinn sich vor dieser Schreibarbeit drücken zu wollen... :whistling:

  • Ich seh's wie BugFix - um das fixen von Bugs kommst du nicht rum ;)

  • *hmmmmm*...

    Gibt es denn eine Möglichkeit, zur Hauptschleife zurück zu kommen?
    Durch sehr abstrakes Programmieren gibt es ja durchaus Funktionen, in Funktionen, in Funktionen, wo dann ein Fehler auftauchen kann.
    Da möchte ich dann nicht jede "void" mit Rückgabewert ausstatten und auf jeder Stufe wieder abfragen und "Return" machen.

    Dann halt auch in tiefer Verschachtelung -> Gehe zur Hauptschleife zurück.

    Return hat da ja nicht sowas praktisches, wie ExitLoop & Co!? :)

    Wenn ich jetzt aber die Hauptschleife z-B. in eine Funktion packen würde und ich die aufrufe, kommt es ja wieder zur bösen Rekursion, oder?! :)

    LG
    Aca

  • Eig. ist das eine Sache/Idee, die mir vor ein paar Tagen im Schlaf gekommen ist :P!
    Ich habe gemerkt, dass meine Daten manchmal kurz nicht erreichbar sind und dann das Programm abstürzt...
    Viele meiner Fehler, wo sie "logisch" auftreten können, sind abgefangen und habe in diese Idee nur etwas "Überlegung" investiert.

    Das einzige Problem, was ich halt sehe, ist, dass wenn Daten "kurz" nicht verfügbar sind, dass ich dann nicht weiß, wie ich das "intelligent" lösen kann... Das Problem besteht schon länger und hatte ich bei vielen Programmen...

    Im letzten Post bin ich ja in die Richtung gegangen, die du meintest, also in Error-Handling überall, wo es notwendig ist.
    Ich weiß nur nicht, wie ich das dort beschriebene Problem lösen kann...


    Mein Ansatz:
    In der Hauptschleife am Anfang die Verbindung überprüfen (Internet/API-Verbindung).
    Wenn irgendwo Arrays erstellt werden, die nur nicht erstellt werden, wenn diese Verbindung tot ist, dann........ -> beende alles und fange wieder in der Hauptschleife neu an.

    Allerdings => Ein einfaches Return reicht nicht, wenn ich in einer verschachtelten Funktion bin und in der Hauptschleife unter dem Funktionsaufruf z.B. noch anderes steht... Und ich will keine Endlos-Rekursion erzeugen, wenn das Programm lange läuft und der Fehler häufiger auftreten KÖNNTE...

    LG
    Aca

    PS: Ist also nur (noch) ne gute Frage, wie sauberes Error-Handling da machbar ist und aussieht. :)

  • Hi,

    Zitat

    ..Überleg mal, wieviel Zeit und Energie du inzwischen aufgewendet hast, um dich vorm Error-Handling zu drücken.
    In der Zeit hättest du auch locker das Errorhandling geschrieben.

    Sehe ich garnicht so.
    Fehler können nur dann abgefangen werden, wenn bekannt ist wo sie überhaupt entstehen können!
    Ich kann 80% meines Codes mit Errorhandling verbraten und trotzdem einen "Fehler" produzieren!

    Ein "einfach so" abstürzendes Programm ist so ziemlich die armseligste Leistung, die ein Programmierer abliefern kann!
    Und die "typischen" Fehlermeldungen von AutoIt gehören da VOLL dazu!

    Ich selbst versuche im Produktivumfeld Fehlermeldungen zu verfassen, die dem User die Möglichkeit geben, mir als dem Programmierer GENAU zu beschreiben, wo, wann und warum ein Fehler aufgetreten ist.
    Und das hat alles nichts mit dem "vorbeugenden Errorhandling" zu tun!
    Es ist ohne weiteres möglich, im Fehlerfall eine Meldung zu generieren im Stile von:
    "Fehler im Modul _Tralala() in der Funktion _blablub().
    Folgende Daten bitte an xyz weitergeben:
    ....
    ....(siehe Beispiel COM-Error)
    "

    Solch eine Fehlermeldung ist produktiv und ich kann SOFORT lokalisieren, wo und ggf. warum ein Fehler aufgetreten ist.
    Die 08/15 AutoIt-Fehlermeldung "Crash an 0xABC0123E in Zeile 0" ist derart ARMSELIG, es wäre besser, das Programm würde kommentarlos seinen Dienst beeenden!
    Aber das kommt davon, wenn man großkotzig über die "BASIC"-Fuzzis lacht, welche schon im ersten IBM-XT von 1983 im ROM einen Basic-Interpreter hatten, welcher eine OnErrorGoto()-Funktion beinhaltete....

  • Hat denn jemand nun ne Lösung für mein Problem / eine Antwort auf meine Frage? :)

    Also nicht die Eingangsfrage, sondern wie man das nun ordentlich machen kann :D.

    LG
    Aca

  • exitloop(2/3/4) geht ja natürlich nur wenn du keine funktionen nimmst, sondern wenn es verschachtelte schleifen sind, aber auch den musst du natürlich mit if-bedingung oder anderweitigem error-handling im code verbinden :)

    • Offizieller Beitrag

    Fehler können nur dann abgefangen werden, wenn bekannt ist wo sie überhaupt entstehen können!


    Genau so sehe ich das auch. Und dazu gehört meiner Meinung nach einfach, wenn es um eine Produktivumgebung geht, dass man halt jedes Datei Lesen/Schreiben, Array Laden etc. auch wirklich handelt. Damit bin ich bisher immer gut gefahren.
    "Unerwartete Fehler" habe ich noch nicht erlebt (bei eigenen Skripten). Aber auch da kann man zumindest zur Auswertung vorbeugen, indem man einfach jede Aktion des Skripts mit Wertangaben loggt bevor der entsprechende Befehl ausgeführt wird. Somit ist der letzte Eintrag im Fehlerfall die Situation an der es gecrasht hat.

  • Zitat

    Hat denn jemand nun ne Lösung für mein Problem / eine Antwort auf meine Frage?

    lies meinen Post nochmal, und den darauffolgenden von Bugfix, dann solltest du wissen, wie man diese "Fehler" abfängt!
    Ein "sauberes" zurückkehren in dein Programm ist doch sowieso nicht möglich, also solltest du im "Fehlerfall" genug informationen bereitstellen, um diese in einer MsgBox darzustellen.
    So mache ich das jedenfalls:

    [autoit][/autoit][autoit][/autoit][autoit]

    OnAutoItExitRegister("Error")

    [/autoit][autoit][/autoit][autoit]

    Global $modulname = "Testscript"
    Global $funktionsname
    Global $Fehlertext

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    loop()

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    Func loop()
    $funktionsname = "Loop"
    Dim $a[10]
    For $i = 1 To 42
    $Fehlertext = "Schleifenvariable $i=" & $i
    $a[$i] = "pft" ;hier kommt der Fehler
    Next
    EndFunc ;==>loop

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    Func Error()
    MsgBox(0, "Fehler aufgetreten", "Fehler im Modul " & $modulname & @CRLF & "Funktion " & $funktionsname & @CRLF & @CRLF & $Fehlertext)
    EndFunc ;==>Error

    [/autoit][autoit][/autoit][autoit][/autoit]
  • Aber die Sache ist ja, dass es mir nicht darum geht, dass der Nutzer Bescheid weiß, sondern dass das Ding nicht zu geht, außer, der Nutzer schließt es via Hand.
    Die einzigen Fehler, die auftauchen, sind halt diese "Datenbasis nicht erreichbar"-Dinger... Und deswegen soll das Ding nicht abstürzen, aber auch nicht einfach nur ein kleines Stückchen überspringen, sondern am Besten wieder ganz raus...

    Aber wenns da keine Möglichkeit gibt, außer den Fehler von innen nach ganz außen zu tragen... Schade... :(

    LG
    Aca

    • Offizieller Beitrag

    Sorry, aber ich kann da kein Problem sehen.
    Was hindert dich denn, deinem Programm so eine Struktur zu verpassen, dass es wie von dir gewünscht reagiert?
    Also du hast folgende Prämissen gesetzt:
    - Datenbasis soll erreicht werden
    - wenn das fehlschlägt, soll das Skript "von vorn" anfangen

    Das kannst du doch ganz simpel mit einer Schleife lösen, in die du noch eine Sicherheit einbaust, damit sie sich nicht totlaufen kann. Etwa so:

    [autoit]


    $iZaehler = 1
    While $iZaehler <= 10 ; == Anzahl der Versuche die Verbindung herzustellen
    $Connection = _ConnectToDatabase() ; == im Fehlerfall am Besten 0 zurückgeben, bei Erfolg 1 od. anderen Wert <> 0
    If $Connection Then ExitLoop
    $iZaehler += 1
    WEnd
    ; == Falls auch nach 10 Versuchen kein Erfolg, mit Meldung beenden
    If Not $Connection Then Exit MsgBox(0, 'Fehler', 'Verbindung zur Datenbank auch nach mehreren Versuchen nicht erfolgreich. Ein schwerwiegendes Problem liegt vor.')

    [/autoit]
  • Zur Verdeutlichung:

    [autoit]

    While 1
    _Function1()
    WEnd

    [/autoit][autoit][/autoit][autoit]

    Func _Function1()
    _Function2()
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func _Function2()
    _Function3()
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func _Function3()
    ; Hier tritt ein Fehler auf, ich will nicht in Function2 und 1 landen...
    EndFunc

    [/autoit]

    Ich könnte ja jetzt bei Function3 abfragen, ob ein Fehler gekommen ist, Fehler returnen, in Function2 abfragen, Fehler returnen, in Function1 abfragen, Fehler returnen und ContinueLoop machen...
    Aber je tiefer das verschachtelt ist, umso komplexer und wirrer wird das Konstrukt...
    Das ist das erste Mal wo ich denke, so ein "gutes altes" GoTo würde mir weiter helfen :P!

    Ich kann ja Schleifen in einer Funktion nicht innerhalb einer anderen Funktion verlassen.

    Ist das verständlich beschrieben :)?!

    LG
    Aca

    • Offizieller Beitrag

    Ich behaupte nach wie vor, dass dein Programm falsch strukturiert ist. Sonst würdest du nie in solche Rekursionen gelangen.
    Ausserdem kann doch die Verbindung zur Datenbank nur an einer Stelle erstellt werden, völlig egal in welcher Rekursionstiefe. Und genau an dieser Stelle läßt du eine Schleife laufen bis Verbindung steht oder definitiv keine Verbindung erstellbar -- und dann kannst du das Programm getrost beenden, da es ja diese Datenanbindung benötigt.

  • Wo ist da die Rekursion? Keine Funktion ruft sich selber auf oder irgendwie im Kreislauf wieder eine Funktion.
    Das ist doch eine normale Verschachtelung? Wenn man abstrakt programmiert.

    Funktion 1 könnte sein, dass es Daten ausliest, die an Funktion 2 übergeben werden, die die Daten interpretiert und formatiert an Funktion 3 übergibt, die die Daten bearbeitet.
    Dann endet die Reihe und es geht wieder in die Hauptschleife, wo alles von vorne beginnt.

    Und ja, die Verbindung kann nur an einer Stelle hergestellt werden, genau daher möchte ich ja, dass wenn in einer anderen Funktion die Verbindung nicht mehr da ist (es also z.B. Arrayfehler deswegen gibt), dass man wieder zum Anfang der Schleife kommt, wo die Verbindung geprüft und evtl. erneut hergestellt wird.^^ (ohne jegliche Rekursion zu erzeugen, weil ich die Hauptschleife auch in eine Funktion packe und in Function3 mit z.B. "If @error Then _Hauptschleife()" diese aufrufe.)

    Liebe Grüße
    Björn

    PS: Vielen Dank, dass du dir die Zeit nimmst, mich zu verstehen ;)