Python wurde unerwartet beendet

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Freumel
User
Beiträge: 69
Registriert: Donnerstag 25. Januar 2018, 13:47

Ich habe ein Selenium-Script geschrieben. Es testet meine Django Application.
Ich möchte einen 24 Stunden Test durchführen und gucken, ob die Ergebnisse auf dem Server den erwarteten entsprechen.

Es ist alles vorbereitet - aber Python beendet das Programm ohne Fehlermeldung als Code.
Ich bekomme eine Meldung "Python wurde unerwartet beendet"

Das Skript führt alle 3 Sekunden die gleiche Aktion durch.
Ich habe also einen Sleep welcher dauerhaft ausgeführt wird.
Im Stil von

Code: Alles auswählen

while True:
	# Code
	sleep(3)
Natürlich sieht die Schleife anders aus. Aber dennoch:
Kann der Programmabbruch daran liegen oder ist das Python Selenium Chromium typisch?

Ich habe ein für etwa 20 Minuten lauffähiges Programm...
Es bricht immer nach etwa der gleichen Zeit ab (+/- 1 Minute).
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Der Rest vom Code in der Schleife wäre aber auch interessant. Befüllst du da irgendwelche Datenstrukturen (Liste, Dict, ...) und werden die vielleicht zu voll im Laufe der Zeit? Wir kennen ja nicht den Umfang der Daten...
Freumel
User
Beiträge: 69
Registriert: Donnerstag 25. Januar 2018, 13:47

snafu hat geschrieben: Dienstag 23. Juni 2020, 16:53 Der Rest vom Code in der Schleife wäre aber auch interessant. Befüllst du da irgendwelche Datenstrukturen (Liste, Dict, ...) und werden die vielleicht zu voll im Laufe der Zeit? Wir kennen ja nicht den Umfang der Daten...
Nicht wirklich.
Mein Tester funktioniert folgender Maßen:

Ich habe eine Anwendung, die möchte ich testen. Es sind insgesamt 3 Aktionen die ich Testen möchte. Ich nenne sie Aktion A, B und C.
Aktion B und C werden sehr unregelmäßig durchgeführt. Aktion A wiederum in Dauerschleife.

Ich habe eine zusätzliche Datenbank angelegt die das Feedback des Servers an den Nutzer in einer Datenbank speichert (ich möchte dass alle Ausgaben gleich sind. Ich hatte vor kurzem den Fall, dass auf der Datenbank meines Servers andere Werte angelegt wurden, als dem Nutzer final angezeigt wurde)
Meine Zusätzliche Anwendung sagt dem Bot welche Aktion durchgeführt werden soll, (in 99% aller Fälle ist es Aktion A). Der Bot führt die Aktion aus, und schickt den relevanten angezeigten Datensatz an eine Datenbank. Anhand des Ergebnisses wird entschieden ob Aktion A, B oder C wieder fällig wird.

Alles was im Programm selbst gefüttert wird, ist die Anzahl aller durchläufe. Hier kommt es etwa zu 500 Durchläufen bevor abgebrochen wird.
Nichts außer das wird am Testscript selbst gespeichert. Es wird kein Dictionary kontinuierlich gefüllt.
Es werden lediglich interne Klassenvariablen (normale Integer) überschrieben.
Freumel
User
Beiträge: 69
Registriert: Donnerstag 25. Januar 2018, 13:47

Na eventuell noch relevant:
Ich rufe den Bot durch folgende Methode auf:

Code: Alles auswählen

def run(self):
        self.driver = settings.get_driver()
        self.driver.get(Server.client_href)
        self.token = self.driver.execute_script('return localStorage.getItem("token")')
        self.signal = 'sleep'
        self.__execute_signal()
Die Execute Signal Methode sieht sinngemäß wie folgt aus:

Code: Alles auswählen

def __execute_signal(self):
        if self.signal == 'A':
            return self.__method_a()
        if self.signal == 'B':
            return self.__method_c()
        
        return self.__method_c()
Innerhalb der Methoden A, B, C werden die Aktionen durchgeführt und das Signal überschrieben.
Anschließend returned jede Methode wieder die __execute_signal() Methode.

Ich habe eine Art endlose Rekursivität erstellt.
Ist das der Böse Fehler?
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Python hat ein Rekursionslimit eingebaut und liefert beim Überschreiten eine passende Fehlermeldung (Exception). Insofern sollte es den Absturz, den du beschreibst, eigentlich nicht geben.

Davon abgesehen ist deine Lösung aber trotzdem unschön. __execute_signal() sollte nicht innerhalb der Handler-Methoden nochmal aufgerufen werden. Wenn du mehrere Signale in "einem Rutsch" verarbeiten willst, dann löse dies besser über eine Schleife. GUI-Frameworks setzen dieses Konzept in Form ihres Event-Loops um. An sowas würde ich mich halten.

https://de.wikipedia.org/wiki/Ereignisschleife
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wobei es den harten Absturz in besonderen Fällen tatsächlich geben kann. Das wird ja von Python eingesetzt damit der dem Programm zugewiesene Stapelspeicher nicht überlaufen und damit zum harten Absturz führen kann. Wenn der Stapelspeicher also besonders klein ist und pro Aufruf wirklich viele oder grosse lokale Variablen (wahrscheinlich in einer C-Erweiterung) auf dem Stapel abgelegt werden, könnte das tatsächlich einen Absturz verursachen, der nicht mehr nett mit einer Ausnahme abgefangen werden kann.

Man könnte das als Zustandsautomaten umsetzen mit `signal` als Zustand und jede der Methoden gibt den Folgezustand zurück, oder `None` falls das beendet werden soll:

Code: Alles auswählen

    def run(self):
        self.driver = settings.get_driver()
        self.driver.get(Server.client_href)
        self.token = self.driver.execute_script(
            "return localStorage.getItem('token')"
        )
        signal = "sleep"
        while signal:
            if signal == "A":
                signal_handler = self._method_a
            elif signal == "B":
                signal_handler = self._method_b
            else:
                signal_handler = self._method_c
            signal = signal_handler()
Das liesse sich mit einem Wörterbuch vereinfachen:

Code: Alles auswählen

        signal_to_handler = {"A": self._method_a, "B": self._method_b}
        signal = "sleep"
        while signal:
            signal = signal_to_handler.get(signal, self._method_c)()
Oder man lässt die Indirektion über Zeichenketten gleich ganz weg:

Code: Alles auswählen

        signal_handler = self._method_c
        while signal:
            signal_handler = signal_handler()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten