Begin Sequence ... Recover ...
Moderator: Moderatoren
- Jan
- Marvin
- Beiträge: 14653
- Registriert: Fr, 23. Sep 2005 18:23
- Wohnort: 49328 Melle
- Hat sich bedankt: 21 Mal
- Danksagung erhalten: 88 Mal
- Kontaktdaten:
Begin Sequence ... Recover ...
Das ist ja nun schon seit Clipper-Zeiten ein Werkzeug zum Abfangen von Laufzeitfehlern. Aber wer von Euch setzt das im realen Entwickler-Leben wirklich noch ein? Wenn ja, in welchen Situationen? Wenn nein, was nehmt Ihr statt dessen?
Warum ich das frage: Ich benutze das eher sparsam. Was aber eher daran liegt das sich mir die Tiefen noch nicht ergründet haben. Was man damit erreichen könnte wenn man es denn wirklich verstünde. Und ich frage mich in dem Zuge halt auch, ob das mit heutigen Programmierstrategien wirklich noch sinnvoll ist, oder ob man die Funktionalitäten nicht besser anders umsetzen sollte.
Jan
Warum ich das frage: Ich benutze das eher sparsam. Was aber eher daran liegt das sich mir die Tiefen noch nicht ergründet haben. Was man damit erreichen könnte wenn man es denn wirklich verstünde. Und ich frage mich in dem Zuge halt auch, ob das mit heutigen Programmierstrategien wirklich noch sinnvoll ist, oder ob man die Funktionalitäten nicht besser anders umsetzen sollte.
Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
- Manfred
- Foren-Administrator
- Beiträge: 21189
- Registriert: Di, 29. Nov 2005 16:58
- Wohnort: Kreis Wesel
- Hat sich bedankt: 210 Mal
- Danksagung erhalten: 67 Mal
Re: Begin Sequence ... Recover ...
Ich benutze es. Und ich habe es auch in meinem übernommenen Projekt drin und da wird es hauptsächlich ähnlich wie Return to Master genutzt. Sprich wenn man innerhalb BEGIn Sequence Funktionen aufruft und dann irgendwann tiefer ein BEAk macht, dann wird direkt alles komplett verlassen.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
- Herbert
- Der Entwickler von "Deep Thought"
- Beiträge: 1991
- Registriert: Do, 14. Aug 2008 0:22
- Wohnort: Gmunden am Traunsee, Österreich
- Danksagung erhalten: 3 Mal
- Kontaktdaten:
Re: Begin Sequence ... Recover ...
Hallo Jan
Du kannst nur soweit Fehler abfangen, wie die von dir benutzten Funktionen auch eine entsprechende Fehlerrückgabe liefern. Fehlt dies oder rufst du Funktionen auf, die nach aussen kommunizieren, wie z.B. Active-X-Aufrufe, so hilft dir das Sequence-Konstrukt, den externen Fehlercode festzuhalten. Dazu verhinderst du den Knall, dass dein Programm nach der Fehlermeldung abtaucht.
Du kannst nur soweit Fehler abfangen, wie die von dir benutzten Funktionen auch eine entsprechende Fehlerrückgabe liefern. Fehlt dies oder rufst du Funktionen auf, die nach aussen kommunizieren, wie z.B. Active-X-Aufrufe, so hilft dir das Sequence-Konstrukt, den externen Fehlercode festzuhalten. Dazu verhinderst du den Knall, dass dein Programm nach der Fehlermeldung abtaucht.
Grüsse Herbert
Immer in Bewegung...
Immer in Bewegung...
- Tom
- Der Entwickler von "Deep Thought"
- Beiträge: 9361
- Registriert: Do, 22. Sep 2005 23:11
- Wohnort: Berlin
- Hat sich bedankt: 101 Mal
- Danksagung erhalten: 361 Mal
- Kontaktdaten:
Re: Begin Sequence ... Recover ...
Es gibt einige grundsätzliche Situationen, in denen ich dieses Konstrukt verwende.
1. Im Web-Server (FTP, HTTP, SOAP, propreitäre Protokolle). Der erzeugt je Verbindung eine Server-Instanz, die in einem eigenen Thread läuft in eine Sequenz eingebettet ist. Tritt hier ein Fehler auf, beendet sich diese Serverinstanz, ohne dass das Programm abschmiert. Die Fehlersituationen werden protokolliert. Damit fangen wir u.a. falsch parametrisierte Abfragen ab, Timeouts und ähnliches (Zugriff auf Tabellen nicht möglich). Trotzdem läuft die Serversoftware zuweilen jahrelang ohne Unterbrechung. Als Rückgabe entsteht ein Fehlercode - abhängig vom verwendeten Protokoll.
2. In einem Servicetool, das Datensicherungen und Konsistenzprüfungen und ähnliches vornimmt, Updates lädt und verteilt usw. Auch das verhält sich entsprechend.
3. In bestimmten Callbacks/Slots, die erfahrungsgemäß Synchronisierungsprobleme haben, etwa XbpBrowse:ForceStable im Kontext des Ownerdrawings (das manchmal langsamer als der UI-Thread ist). Hier ersparen wir uns z.B. auch bei der Ermittlung von Zellenfarben die Prüfung der benutzererfassten Daten. Schmiert die in eine Sequenz eingebettete Auswertung der dazugehörigen Codeblöcke ab, defaultet das System schlicht auf die Standardfarben.
4. Beim Direktexport z.B. nach Excel. Situationen wie bereits geöffnete Excel-Dateien oder schlicht fehlende Excel-Instanzen lassen sich leicht abfangen, doch eine Trialversion von Office verhält sich sehr eigenartig, lässt aber die Initialisierung des Controls zu. Es ist sehr schwer, auf alle denkbaren Fehlersituationen zu reagieren, aber es ist blöd, wenn daraus Laufzeitfehler entstehen. Eine Sequenz erlaubt den relativ eleganten Umgang mit dieser Situation.
5. Beim Umgang mit Datenbankservern und ODBC-Datenquellen in Xbase-Notation. Das merzen wir zwar derzeit gerade aus, aber es wird noch an einigen Stellen verwendet. Statt alle denkbaren Client-Errors abzufangen, die ohnehin selten umgangen werden können, fällt das System an dieser Stelle auf die Notfallebene, wenn ein Laufzeitfehler generiert wird. Es merkt sich schlicht die Vorgänge und versucht sie später abermals.
6. Simpel: Beim Versuch, eine DBE zu laden.
7. Im Fehlersystem, wenn es Dateiöffnungsfehler gibt, die Dateien aber vorhanden sind - vor allem im Kontext von (vielen) Indexdateien, die nicht selten Virenscanner in die Knie zwingen, wodurch das Betriebssystem Timeouts generiert.
Und so weiter.
Es ist nicht unelegant oder "old-fashioned", diese Systematik zu verwenden. Ganz im Gegenteil ist das ein mächtiges Tool, um Situationen abzufangen, die sich der Vorhersehbarkeit entziehen, ohne dass man falsch programmiert hätte. Auch ein einfaches "DbUseArea()" kann ja fehlschlagen, obwohl die Tabelle vorhanden ist und theoretisch im Shared-Modus geöffnet werden kann. Aber ein findiger Anwender hat sie manipuliert, oder sie ist physisch beschädigt. Bettet man das also in eine Sequenz ein, kann man in der Anwendung darüber informieren, dass es ein Problem zu geben scheint, ohne den Anwender mit Laufzeitfehlern zu konfrontieren.
1. Im Web-Server (FTP, HTTP, SOAP, propreitäre Protokolle). Der erzeugt je Verbindung eine Server-Instanz, die in einem eigenen Thread läuft in eine Sequenz eingebettet ist. Tritt hier ein Fehler auf, beendet sich diese Serverinstanz, ohne dass das Programm abschmiert. Die Fehlersituationen werden protokolliert. Damit fangen wir u.a. falsch parametrisierte Abfragen ab, Timeouts und ähnliches (Zugriff auf Tabellen nicht möglich). Trotzdem läuft die Serversoftware zuweilen jahrelang ohne Unterbrechung. Als Rückgabe entsteht ein Fehlercode - abhängig vom verwendeten Protokoll.
2. In einem Servicetool, das Datensicherungen und Konsistenzprüfungen und ähnliches vornimmt, Updates lädt und verteilt usw. Auch das verhält sich entsprechend.
3. In bestimmten Callbacks/Slots, die erfahrungsgemäß Synchronisierungsprobleme haben, etwa XbpBrowse:ForceStable im Kontext des Ownerdrawings (das manchmal langsamer als der UI-Thread ist). Hier ersparen wir uns z.B. auch bei der Ermittlung von Zellenfarben die Prüfung der benutzererfassten Daten. Schmiert die in eine Sequenz eingebettete Auswertung der dazugehörigen Codeblöcke ab, defaultet das System schlicht auf die Standardfarben.
4. Beim Direktexport z.B. nach Excel. Situationen wie bereits geöffnete Excel-Dateien oder schlicht fehlende Excel-Instanzen lassen sich leicht abfangen, doch eine Trialversion von Office verhält sich sehr eigenartig, lässt aber die Initialisierung des Controls zu. Es ist sehr schwer, auf alle denkbaren Fehlersituationen zu reagieren, aber es ist blöd, wenn daraus Laufzeitfehler entstehen. Eine Sequenz erlaubt den relativ eleganten Umgang mit dieser Situation.
5. Beim Umgang mit Datenbankservern und ODBC-Datenquellen in Xbase-Notation. Das merzen wir zwar derzeit gerade aus, aber es wird noch an einigen Stellen verwendet. Statt alle denkbaren Client-Errors abzufangen, die ohnehin selten umgangen werden können, fällt das System an dieser Stelle auf die Notfallebene, wenn ein Laufzeitfehler generiert wird. Es merkt sich schlicht die Vorgänge und versucht sie später abermals.
6. Simpel: Beim Versuch, eine DBE zu laden.
7. Im Fehlersystem, wenn es Dateiöffnungsfehler gibt, die Dateien aber vorhanden sind - vor allem im Kontext von (vielen) Indexdateien, die nicht selten Virenscanner in die Knie zwingen, wodurch das Betriebssystem Timeouts generiert.
Und so weiter.
Es ist nicht unelegant oder "old-fashioned", diese Systematik zu verwenden. Ganz im Gegenteil ist das ein mächtiges Tool, um Situationen abzufangen, die sich der Vorhersehbarkeit entziehen, ohne dass man falsch programmiert hätte. Auch ein einfaches "DbUseArea()" kann ja fehlschlagen, obwohl die Tabelle vorhanden ist und theoretisch im Shared-Modus geöffnet werden kann. Aber ein findiger Anwender hat sie manipuliert, oder sie ist physisch beschädigt. Bettet man das also in eine Sequenz ein, kann man in der Anwendung darüber informieren, dass es ein Problem zu geben scheint, ohne den Anwender mit Laufzeitfehlern zu konfrontieren.
Herzlich,
Tom
Tom
- brandelh
- Foren-Moderator
- Beiträge: 15696
- Registriert: Mo, 23. Jan 2006 20:54
- Wohnort: Germersheim
- Hat sich bedankt: 66 Mal
- Danksagung erhalten: 33 Mal
- Kontaktdaten:
Re: Begin Sequence ... Recover ...
Der DBEDITOR() nutzt das um z.B. Laufzeitfehler bei Öffnen einer Datei abzufangen.
zwischen file(cFile) und use (cFile) könnte ja gerade gelöscht worden sein ... oder schreibschutz ...
Oder Bei selbst gebauten Filterangaben etc. würde beim &(cFilter) ein Laufzeitfehler das Programm beenden.
Das will kein Anwender sehen
Irgendwo habe ich mal gelesen, dass man früher (DOS ?) zuerst alle Fehler abgeprüft hätte, das wäre aber altmodisch.
Modern wäre es im (seltenen) Laufzeitfehlerfall diesen zu behandeln.
Bei Xbase++ ist das BEGIN SEQUENCE ... anderswo nennt man es TRY ...
zwischen file(cFile) und use (cFile) könnte ja gerade gelöscht worden sein ... oder schreibschutz ...
Oder Bei selbst gebauten Filterangaben etc. würde beim &(cFilter) ein Laufzeitfehler das Programm beenden.
Das will kein Anwender sehen
Irgendwo habe ich mal gelesen, dass man früher (DOS ?) zuerst alle Fehler abgeprüft hätte, das wäre aber altmodisch.
Modern wäre es im (seltenen) Laufzeitfehlerfall diesen zu behandeln.
Bei Xbase++ ist das BEGIN SEQUENCE ... anderswo nennt man es TRY ...
Gruß
Hubert
Hubert
- Tom
- Der Entwickler von "Deep Thought"
- Beiträge: 9361
- Registriert: Do, 22. Sep 2005 23:11
- Wohnort: Berlin
- Hat sich bedankt: 101 Mal
- Danksagung erhalten: 361 Mal
- Kontaktdaten:
Re: Begin Sequence ... Recover ...
Wenn man allerdings zu allgemein wird ("Es gibt ein Problem beim Öffnen der Datei ..."), also einfach alles, was irgendwie Fehler erzeugen könnte, in Sequenzen einbettet, verhindert man andererseits, dass echte Fehlersituationen schnell und ursächlich erkannt werden können. Man sollte sich also genau überlegen, auf welchem Level man das einsetzt.
Das von Hubert genannte Problem mit dem "selbstgebauten" Filter ist gut. Ich mache so etwas in einem Servicetool, das für unsere Supportmitarbeiter programmiert wurde und das u.a. erlaubt, Abfragen (Filter, Suche) auf Tabellen selbst zu formulieren. Da gibt es zwar einen Assistenten, der bei der Generierung solcher Abfragen hilft (Feldauswahl, Abfrage mit Vorgaben abhängig vom Feldtyp), aber man kann auch direkt Abfragen eintippen. Die Evaluation erfolgt dann in einer Sequenz. Scheitert die, gab es einen Syntaxfehler, und ein entsprechender Hinweis erscheint. Danach kann man dann die Abfrage korrigieren. Anders wäre eine Syntaxprüfung ein haarsträubender Aufwand.
Das von Hubert genannte Problem mit dem "selbstgebauten" Filter ist gut. Ich mache so etwas in einem Servicetool, das für unsere Supportmitarbeiter programmiert wurde und das u.a. erlaubt, Abfragen (Filter, Suche) auf Tabellen selbst zu formulieren. Da gibt es zwar einen Assistenten, der bei der Generierung solcher Abfragen hilft (Feldauswahl, Abfrage mit Vorgaben abhängig vom Feldtyp), aber man kann auch direkt Abfragen eintippen. Die Evaluation erfolgt dann in einer Sequenz. Scheitert die, gab es einen Syntaxfehler, und ein entsprechender Hinweis erscheint. Danach kann man dann die Abfrage korrigieren. Anders wäre eine Syntaxprüfung ein haarsträubender Aufwand.
Herzlich,
Tom
Tom
- Jan
- Marvin
- Beiträge: 14653
- Registriert: Fr, 23. Sep 2005 18:23
- Wohnort: 49328 Melle
- Hat sich bedankt: 21 Mal
- Danksagung erhalten: 88 Mal
- Kontaktdaten:
Re: Begin Sequence ... Recover ...
Hallo,
vielen Dank für Eure Anmerkungen dazu, und die vielen Anwendungsbeispiele. Das dürfte also wohl in der Tat immer noch sehr aktuell sein.
Könnt Ihr mir vielleicht mal zwei oder drei Beispiele posten, wie man sowas sinnnig aufbaut? Wie so häufig beiße ich bei den Alaska-Beispielen in der Doku irgendwie auf Granit. Da fehlt mir jegliche Phantasie der realen Umsetzungsmöglichkeit.
Jan
vielen Dank für Eure Anmerkungen dazu, und die vielen Anwendungsbeispiele. Das dürfte also wohl in der Tat immer noch sehr aktuell sein.
Könnt Ihr mir vielleicht mal zwei oder drei Beispiele posten, wie man sowas sinnnig aufbaut? Wie so häufig beiße ich bei den Alaska-Beispielen in der Doku irgendwie auf Granit. Da fehlt mir jegliche Phantasie der realen Umsetzungsmöglichkeit.
Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
- brandelh
- Foren-Moderator
- Beiträge: 15696
- Registriert: Mo, 23. Jan 2006 20:54
- Wohnort: Germersheim
- Hat sich bedankt: 66 Mal
- Danksagung erhalten: 33 Mal
- Kontaktdaten:
Re: Begin Sequence ... Recover ...
in der Hilfe zu BEGIN SEQUENCE stehen die zwei wichtigsten.
1. aus tiefer Verschachtelung gezielt mehrere Ebenen herausspringen.
2. eine lokale Fehlerbehandlung, dann muss man aber auch ein Error-Objekt übergeben und auswerten.
Zu Toms Anmerkung, einfach alle Fehler auf "Es ist ein Fehler aufgetreten" zu leiten wäre sicher nicht dienlich !
Aber so kann man ohne die Errorsys global zu ändern lokal Fehler bearbeiten. Aber NIE den otherwise Zweig für alle anderen Fehler mit Xbase++ Standardbehandlung vergessen.
Wie immer muss man wissen was man macht und warum man es so macht
1. aus tiefer Verschachtelung gezielt mehrere Ebenen herausspringen.
2. eine lokale Fehlerbehandlung, dann muss man aber auch ein Error-Objekt übergeben und auswerten.
Zu Toms Anmerkung, einfach alle Fehler auf "Es ist ein Fehler aufgetreten" zu leiten wäre sicher nicht dienlich !
Aber so kann man ohne die Errorsys global zu ändern lokal Fehler bearbeiten. Aber NIE den otherwise Zweig für alle anderen Fehler mit Xbase++ Standardbehandlung vergessen.
Wie immer muss man wissen was man macht und warum man es so macht
Gruß
Hubert
Hubert
- Manfred
- Foren-Administrator
- Beiträge: 21189
- Registriert: Di, 29. Nov 2005 16:58
- Wohnort: Kreis Wesel
- Hat sich bedankt: 210 Mal
- Danksagung erhalten: 67 Mal
Re: Begin Sequence ... Recover ...
Code: Alles auswählen
bSaveError := ErrorBlock( {|e|BREAK(e)})
DO WHILE ! (::nArea)->(Eof())
BEGIN SEQUENCE
(oDbNeu:nArea)->(DbAppend())
AEval(::aTempArray, {|x,nI| Eval(::aTempArray[nI]) })
IF ++nZaehler % nModulo = 0 .OR. nZaehler < 100
oStatic3:SetCaption(Alltrim(Str(nZaehler)))
ENDIF
(::nArea)->(DbSkip())
RECOVER USING oError
altd() // der dient der Fehlersuche
oSysPara:oPruefen:fehlerbehandlung(oError,self)
END SEQUENCE
ErrorBlock(bSaveError)
ENDDO
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
- Tom
- Der Entwickler von "Deep Thought"
- Beiträge: 9361
- Registriert: Do, 22. Sep 2005 23:11
- Wohnort: Berlin
- Hat sich bedankt: 101 Mal
- Danksagung erhalten: 361 Mal
- Kontaktdaten:
Re: Begin Sequence ... Recover ...
Hallo, Jan.
Ein weiteres Beispiel wäre die Reparatur korrupter Tabellen. Leider geschieht das zuweilen ja - mittendrin steht plötzlich Garbage, oder die gute alte DBT hat die 2-Gigabyte-Grenze überschritten, weshalb es Lesefehler beim Zugriff auf die Tabelle gibt. Die Lösung besteht darin, den Zugriff auf die Felder (FieldGet()), der in solchen Situationen ja auch Fehler erzeugt, beim Umkopieren der Daten in die korrigierte Tabelle in eine Sequenz einzubetten - und einfach zum nächsten Feld zu springen. Dadurch erhält man ohne Laufzeitfehler eine instandgesetzte Tabelle, die man dann weiter inhaltlich prüfen kann.
Hier ein Beispiel zu einer "selbstgebauten" Filterbedingung:
Alles zwischen "RECOVER" und "END SEQUENCE" wird nur angefasst, wenn es im Code zwischen "BEGIN SEQUENCE" und "RECOVER" einen Laufzeitfehler gab.
Ein weiteres Beispiel wäre die Reparatur korrupter Tabellen. Leider geschieht das zuweilen ja - mittendrin steht plötzlich Garbage, oder die gute alte DBT hat die 2-Gigabyte-Grenze überschritten, weshalb es Lesefehler beim Zugriff auf die Tabelle gibt. Die Lösung besteht darin, den Zugriff auf die Felder (FieldGet()), der in solchen Situationen ja auch Fehler erzeugt, beim Umkopieren der Daten in die korrigierte Tabelle in eine Sequenz einzubetten - und einfach zum nächsten Feld zu springen. Dadurch erhält man ohne Laufzeitfehler eine instandgesetzte Tabelle, die man dann weiter inhaltlich prüfen kann.
Hier ein Beispiel zu einer "selbstgebauten" Filterbedingung:
Code: Alles auswählen
* "cAlias" enthält den Alias der Tabelle, in der gesucht werden soll, "cSuchbedingung" den Suchbegriff
LOCAL oError, bSaveError
bSaveError := ErrorBlock() // alten Error-Codeblock sichern
ErrorBlock( {|e| Break(e)} ) // neuen Error-Codeblock etablieren - Break im Fehlerfall (Sprung zum "Recover")
BEGIN SEQUENCE
DbSelectArea(cAlias)
LOCATE FOR &cSuchBedingung // geht auch eleganter
RECOVER USING oError
MsgBox('Der Suchbegriff ist falsch!','Suche')
END SEQUENCE
ErrorBlock(bSaveError) // alten Error-Codeblock restaurieren
Herzlich,
Tom
Tom