ubuntuusers.de

[Python] Ein Programm starten, überwachen (bleibt machnmal hängen), beenden und neu starten

Status: Ungelöst | Ubuntu-Version: Ubuntu 7.10 (Gutsy Gibbon)
Antworten |

Grek336

Anmeldungsdatum:
28. November 2007

Beiträge: 408

Ich habe eine gepatchte Version von Last-Exit die manchmal hängen bleibt (ein bekannte aber noch ungelöstes Problem).

Damit ich nicht immer selber kontrollieren muss ob Last-Exit noch aufnimmt, es wenn es wieder stehen geblieben ist manuelle beenden und wieder dieser neu starten muss, wollte ich den ganzen Vorgang automatisieren.

Bei der Wahl zwischen einem Script und einem Programm habe ich mich für ein Programm und zwar in Python entschieden.

Ich dachte mir den Ablauf des Programms zunächst wie folgt:

last-exit starten
Schleife:
  1 Minute warten
  kontrollieren ob Last-Exit noch läuft:
    Nein: last-exit beenden; last-exit starten
SchleifeEnde

Manchmal kommt es vor das sich Last-Exit einfach beendet. Ich weiß nicht ob es einen Fehlercode zurückgibt oder etwas in den Fehler- oder Ausgabekanal schreibt. Aber ich vermute mal das es das tut.

Darum meine zweite Version:

last-exit starten
Schleife:
  Warten (z.B. 1 Minute)
  Wird Last-Exit noch ausgeführt?
    Nein: Ist last-exit abgestürzt?
      Nein: Programm beenden
      Ja: last-exit neu starten
    Ja: Nimmt Last-Exit noch auf?
      Nein: last-exit beenden; last-exit neu starten
SchleifeEnde

Um zu kontrollieren ob Last-Exit noch aufnimmt habe ich folgendes ermittelt:

Last-Exit speichert den gerade aufgenommenen Titel in der Datei /tmp/lastexit-<Benutzername>.

  • Wenn das Änderungsdatum der Datei zu lange zurückliegt (z.B. mehr als 30 Sekunden) nimmt Last-Exit nicht mehr auf.

  • Wenn die Datei längere Zeit nicht existiert nimmt Last-Exit nicht mehr auf.

Darum meine dritte Version:

last-exit starten
Schleife:
  1 Minute warten
  Wird Last-Exit noch ausgeführt?
    Nein: Ist last-exit abgestürzt?
      Nein: Programm beenden
      Ja: last-exit neu starten
    Ja: Existiert die Temporäre-Datei?
      Ja: War die letzte Änderung vor mehr als 30 Sekunden?
        Ja: last-exit beenden; last-exit neu starten
      Nein: 10 Sekunden warten; 
            Existiert die Temoräre-Datei?
        Nein: last-exit beenden; last-exit neu starten
SchleifeEnde
  • Falls sich der Prozess beendet hat kontrolliere ob es einen Fehlercode zurückgegeben hat oder ob etwas in den Ausgaben im Fehler-oder Ausgabekanal auf einen Absturz hindeutet.

    • Falls es sich um einen Absturz handelt last-exit neu starten sonst ist die Aufgabe erledigt

Meine vierte Version ist mehr hypothetisch weil ich nicht genau weiß wie sich last-exit bei einem Absturz wirklich verhält:

last-exit starten
Schleife:
  1 Minute warten
  Wird Last-Exit noch ausgeführt?
    Nein: Gab es einen Fehlercode?
      Nein: Gab es einen Ausgabe die auf einen Absturz hindeutet?
        Nein: Programm beenden
        Ja: last-exit neu starten
      Ja: last-exit neu starten
    Ja: Existiert die Temporäre-Datei?
      Ja: War die letzte Änderung vor mehr als 30 Sekunden?
        Ja: last-exit beenden; last-exit neu starten
      Nein: 10 Sekunden warten; 
            Existiert die Temoräre-Datei?
        Nein: last-exit beenden; last-exit neu starten
SchleifeEnde

Zunächst hatte ich ein Pythonprogramm (Gutsy hat Python 2.5) geschrieben, um festzustellen ob die Methode mit der ich ermitteln will ob die Temporäre-Datei existiert und wann sie das letzte mal geändert wurde, auch funktioniert. Das Programm sieht chaotisch aus weil ich nach 20 Jahren Programmierabstinenz das Programmieren anscheinend ziemlich verlernt habe. Auch Python selber und die Entwicklungsumgebung DrPython bereiten mir Probleme. Da DrPython keinen Debugger hat, der es einem ermöglicht das Programm schrittweise auszuführen, habe ich zur Uralt-Methode mit print gegriffen, insbesondere nachdem verschiedene Versionen meines Testprogramms hängengebleiben sind und ich DrPython beenden und neu starten musste um weiterzumachen. Mittlerweile benutze ich Eric 3.9.5 (die Version 4 gibt es für Gutsy nicht) das zwar einen Debugger und Einzelschrittausführung hat, für meine Zwecke aber wohl zu groß und überladen ist.

Das Testprogramm in seiner Endversion:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import time

DateiNichtGefunden = 0
MaximaleZeitDifferenz = 0.0
MinimaleZeitDifferenz = 0.0

print "-1"
print "Start"
#Programm=Starte("last-exit "lastfm://artist/Dannii Minogue/similarartists"")
print "0"
while True:
	print "1"
	time.sleep(1)
	print "2"
	try:
		print "3"
		DateiZeit = os.path.getatime("/tmp/lastexit-michael")
		print "4"
	except OSError:
		print "5"
		if DateiNichtGefunden > 0:
			print "6"
			print "last-exit hängt weil die temporäre Datei mehr als 60 Sekunden lang nicht existiert"
			print "7"
			print "Systemzeit:", time.asctime(time.localtime(time.time()))
			print "8"
			#Beende(Programm)
			#Programm=Starte("last-exit "lastfm://artist/Dannii Minogue/similarartists"")
			#DateiNichtGefunden = 0
			#continue
			break
			print "9"
		else:
			print "10"
			print "Datei nicht gefunden"
			print "11"
			DateiNichtGefunden = DateiNichtGefunden+1
			print "12"
			continue
			print "13"
	else:	
		print "14"
		SystemZeit = time.time()
		print "15"
		DateiNichtGefunden = 0
		print "16"
		ZeitDifferenz = DateiZeit-SystemZeit
		print "17"
		if ZeitDifferenz < -60 :
			print "18"
			print "last-exit hängt weil in die temporäre Datei mehr als 60 Sekunden lang nichts geschrieben wurde"
			print "19"
			print "Dateizeit:", time.asctime(time.localtime(DateiZeit)), "; " , "Systemzeit:", time.asctime(time.localtime(SystemZeit))
			print "20"
			#Beende(Programm)
			#Programm=Starte("last-exit "lastfm://artist/Dannii Minogue/similarartists")
			#continue
			break
			print "21"
		else:
			print "22"
			if ZeitDifferenz < MinimaleZeitDifferenz :
				print "23"
				MinimaleZeitDifferenz = ZeitDifferenz
				print "24"
				print "Minimale Zeitdifferenz: ", MinimaleZeitDifferenz
				print "25"
			if ZeitDifferenz > MaximaleZeitDifferenz :
				print "26"
				MaximaleZeitDifferenz = ZeitDifferenz
				print "27"
				print "Maximale Zeitdifferenz: ", MaximaleZeitDifferenz
				print "28"
			continue
			print "29"

Nachdem ich einigermaßen sicher was das meine Erkennungsmethode grundsätzlich funktioniert habe ich versucht last-exit von Python aus aufzurufen und zu beenden. Das Programm sieht nach etlichen Verschlimmbesserungen noch chaotischer aus.

Das Überwachungsprogramm Last-ExitWatchdog (Stand ca. 2 Uhr Nachts an Neujahr):

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import time
import subprocess

DateiNichtGefunden = 0
MaximaleZeitDifferenz = 0.0
MinimaleZeitDifferenz = 0.0
WarteZeit = 60
KommandoStartLastExit = ["/bin/sh","last-exit","lastfm://artist/Dannii Minogue/similarartists"]
#KommandoStartLastExit = ["last-exit","lastfm://artist/Dannii Minogue/similarartists"]

#LastExitURL = sys.argv[1]

LastExit = subprocess.Popen(KommandoStartLastExit)
KommandoTermLastExit = ["/bin/kill", "-TERM ", str(LastExit.pid)] 
KommandoKillLastExit = ["/bin/kill", "-KILL ", str(LastExit.pid)]
while True:
    #time.sleep(WarteZeit)
    LastExitRueckgabewert = LastExit.poll
    if  LastExit.returncode <> None:
        if LastExit.returncode == 0:
            break
        else:
            LastExit = subprocess.Popen(KommandoStartLastExit)
            KommandoTermLastExit = ["/bin/kill", "-TERM ", str(LastExit.pid)] 
            KommandoKillLastExit = ["/bin/kill", "-KILL ", str(LastExit.pid)]
            DateiNichtGefunden = 0
            continue
    else:
        try:
            DateiZeit = os.path.getatime("/tmp/lastexit-michael")
        except OSError:
            if DateiNichtGefunden > 0 :
                Kill = subprocess.Popen(KommandoTermLastExit)
                time.sleep(WarteZeit/10)
                if Kill.returncode <> None :
                    if Kill.returncode == 0:
                        LastExit = subprocess.Popen(KommandoStartLastExit)
                        KommandoTermLastExit = ["/bin/kill", "-TERM ", str(LastExit.pid)] 
                        KommandoKillLastExit = ["/bin/kill", "-KILL ", str(LastExit.pid)]
                        DateiNichtGefunden = 0
                        continue
                    else: 
                        Kill = subprocess.Popen(KommandoKillLastExit)
                        time.sleep(WarteZeit/10)
                        if Kill.returncode <> None :
                            if Kill.returncode == 0:
                                LastExit = subprocess.Popen(KommandoStartLastExit)
                                KommandoTermLastExit = ["/bin/kill", "-TERM ", str(LastExit.pid)] 
                                KommandoKillLastExit = ["/bin/kill", "-KILL ", str(LastExit.pid)]
                                DateiNichtGefunden = 0
                                continue
                            else:
                                print("Last-Exit konnte nicht beendet werden.")
                                break
                        else:
                            print("kill -KILL reagiert nicht")
                            break
                else:
                    print("kill -TERM reagiert nicht")
                    break
            else:
                DateiNichtGefunden = DateiNichtGefunden+1
                continue
        else:	
            SystemZeit = time.time()
            DateiNichtGefunden = 0
            ZeitDifferenz = DateiZeit-SystemZeit
            if ZeitDifferenz < -WarteZeit :
                Kill = subprocess.Popen(KommandoTermLastExit)
                time.sleep(WarteZeit/10)
                if Kill.returncode <> None :
                    if Kill.returncode == 0:
                        LastExit = subprocess.Popen(KommandoStartLastExit)
                        KommandoTermLastExit = ["/bin/kill", "-TERM ", str(LastExit.pid)] 
                        KommandoKillLastExit = ["/bin/kill", "-KILL ", str(LastExit.pid)]
                        DateiNichtGefunden = 0
                        continue
                    else: 
                        Kill = subprocess.Popen(KommandoKillLastExit)
                        time.sleep(WarteZeit/10)
                        if Kill.returncode <> None :
                            if Kill.returncode == 0:
                                LastExit = subprocess.Popen(KommandoStartLastExit)
                                KommandoTermLastExit = ["/bin/kill", "-TERM ", str(LastExit.pid)] 
                                KommandoKillLastExit = ["/bin/kill", "-KILL ", str(LastExit.pid)]
                                DateiNichtGefunden = 0
                                continue
                            else:
                                print("Last-Exit konnte nicht beendet werden.")
                                break
                        else:
                            print("kill -KILL reagiert nicht")
                            break
                else:
                    print("kill -TERM reagiert nicht")
                    break
            else:
                continue

Mal abgesehen von meinen mehr als bescheidenen Programmierungskünsten habe ich es bis jetzt nicht zustande gebracht last-exit so aufzurufen das es nach dem beenden einen returncode liefert.

Wenn ich last-exit manuell beende bleibt es (laut Systemüberwachung) als Zombie zurück und das Pythonprogramm erkennt nicht das es beendet wurde. Mein Versuch last-exit über die Shell aufzurufen führte nur zu einem neuen Prozess sh dem anscheinend keine Argumente übergeben wurden (laut Systemüberwachung). Dasselbe passiert bei dem Versuch kill aufzurufen (dabei musste ich erfahren das es zwei kill Befehle gibt. Den built-in Befehl der Shell und ein echtes Programm /bin/kill was mich zusätzlich verwirrt hat) um den vorher aufgerufenen Prozess zu beenden. Allerdings vermute ich das es eine Möglichkeit gibt den last-exit-Prozess direkt von Python aus zu beenden ohne externes Programm. Ich weiß nur nicht welche.

Die Dokumentationen sind leider alle in englisch und mit dieser Sprache stehe ich seit meiner Grundschulzeit auf Kriegsfuß. Ich habe zwar noch ein Buch "Python Referenz David M. Beazley (2001)" als PDF-Datei, aber das nutzt mir leider nichts da es gerade os, subprozess und popen nicht weiter erklärt.

Es ist mir auch nicht gelungen durch googlen etwas passendes im Internet zu finden. Das was ich gefunden und ausprobiert habe funktioniert leider alles nicht.

Was ich benötige wäre :

  • last-exit so aufzurufen wie es geschieht wenn ich es über "GNOME-Menü → Anwendung → Last-Exit" aufrufe nur zusätzlich mit dem Parameter für die Last-FM-URL.

  • Eine Möglichkeit festzustellen ob der Prozess noch läuft.

    • Falls nicht: Returncode und die Letzten Ausgaben des Prozesses.

    • Falls ja: Eine Möglichkeit ihn zu beenden. Manchmal ist Last-Exit hartnäckig und lässt sich nicht durch Schließen beenden sonder muss im nachfolgenden "Die Anwendung reagiert nicht mehr"-Dialog zwangsweise beendet werden.

last-exit in der Shell aufgerufen starte übrigends ein Script

/usr/bin/last-exit:

1
2
3
4
5
#!/bin/bash

export MONO_GAC_PREFIX=$MONO_GAC_PREFIX:/usr

exec -a "last-exit" /usr/bin/mono  /usr/lib/last-exit/last-exit.exe "$@"

Grüße aus Berlin und allen Gesundheit, Glück und das alle Wünsche im neuen Jahr in Erfüllung gehen

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4672

Wohnort: Berlin

Das hat nichts mit Programmierabstinenz oder einem fehlenden Debugger zu tun, wenn man bei einem "Riesenklops" von 80 Zeilen, mit ca. 90 Anweisungen und 27 Verzweigungen, die bis bis zu 8 Ebenen tief verschachtelt sind, nicht mehr den Überblick behält.

Bitte das Tutorial aus der Python-Dokumentation durcharbeiten, mindestens bis einschliesslich Funktionen, oder halt irgend etwas deutschsprachiges, und dann den ganzen Quelltext auf einzelne Funtkionen aufteilen, die man überblicken kann und einzeln testen kann. Damit dürfte das ganze wesentlich kürzer werden, weil der jetzige Quelltext schon fast unverschämt viel "copy'n'paste"-Code in den einzelnen Zweigen enthält. Und so überlange Zeilen entstehen dann auch nicht so schnell.

Warum startest Du das Programm über eine Shell? Dann weisst Du ja nie, ob der Rückgabewert von der Shell oder vom Programm stammt.

Der <>-Operator ist veraltet und ist bei Python 3.0 mittlerweile aus der Sprache geflogen. Besser != verwenden.

Antworten |