Externes Skript starten + nicht auf Beendigung warten + WorkDir ändern

Code-Stücke können hier veröffentlicht werden.
Antworten
Zeruat
User
Beiträge: 2
Registriert: Freitag 8. Dezember 2017, 20:27

Freitag 8. Dezember 2017, 20:47

Heyho allesamt,

erst einmal sorry für den nicht ganz so klaren Titel!

Es geht um folgendes:


Ich habe ein kleines Programm geschrieben, welches als "Pseudo-Daemon" 24/7 auf meinem Server laufen soll. Leider bekomme ich noch manchmal Fehler, woraufhin das Programm abstürzt.
Um dem vorzubeugen, habe ich eine PHP Seite eingerichtet, welche mir beim Aufruf eine start.txt erstellt, sodass ich kurz und schmerzlos das Skript neu starten kann. Das Ganze soll mit einem zweiten Skript realisiert werden.
Undzwar mit dieser Logik: Das zweite Skript verbindet sich alle 30 Sekunde per FTP mit dem Server und schaut, ob die erstellte Datei vorhanden ist. Falls ja, soll die vorherige Instanz des eigentlichen Programms geschlossen werden (taskkill) und daraufhin noch einmal neu gestartet werden.
Falls nein, soll in 30 Sekunden wieder nachgeschaut werden.

Mein Problem ist jetzt folgendes:
1. das Verzeichnis in dem das Skript ausgeführt werden soll, ist ein anderes als das wo es momentan liegt.
2. da das auszuführende Skript dann in Endlosschleife läuft, soll nicht auf die Beendigung des gestarteten Skripts gewartet werden

Ich habe schon den ganzen Mittag gegooglet, und es mit os.spawn*, subprocess.call/run, popen usw.. probiert, aber leider einfach keine Lösung zusammengebaut bekommen...

Code: Alles auswählen

from ftplib import FTP
import time
import os
import subprocess

global ftp

run = 'true'
startfile = 'start.txt'

def connectftp():

    global ftp

    ftp = FTP('SERVER')
    ftp.login('USERNAME,'PASSWORT')
    ftp.cwd('DOCUMENTROOT')

def getcomfile():

    global ftp

    file_list = ftp.nlst()
    if startfile in file_list:
        ftp.delete(startfile)
        os.system('taskkill /IM conhost.exe /f')
        os.system('taskkill /IM cmd.exe /f')
        ## STARTE 'python menu.py -autoload 120 new' in 'D:\Refactored'
        file_list = ['']
    else:
        pass


connectftp()
while run == 'true':
    getcomfile()
    time.sleep(30)
Ich wäre echt dankbar, wenn mir da jemand zu helfen wüsste !

Edit: Das Ganze läuft auf einem Windows System.

P.S.: Sorry wenns im falschen Topic gelandet ist, bin neu hier
P.P.S: Mist, ich glaube es ist im falschen Topic gelandet, wäre super wenn ein Moderator es verschieben würde.


LG,
Zeruat
__deets__
User
Beiträge: 3693
Registriert: Mittwoch 14. Oktober 2015, 14:29

Freitag 8. Dezember 2017, 23:35

Warum so kompliziert? Zum ersten kann Python viele Fehler selbst anfangen. Abef selbst wenn wir das Neustart Modell beibehalten, was durchaus gut ist, hat das doch nix mit php und ftp zu tun. Schreib eine Systemd Unit. Oder ein wrapper Skript, welches dein eigentliches Skript startet und bei bedarf neu startet.
Zeruat
User
Beiträge: 2
Registriert: Freitag 8. Dezember 2017, 20:27

Samstag 9. Dezember 2017, 00:14

Danke für die rasch Antwort!

Die Fehlerproblematik ist eine andere Baustelle...

Habe vergessen zu erwähnen dass das Skript auf einem anderen (nicht Web-) Server läuft.
Das eigentliche "Haupt"Skript lädt Daten aus dem Internet runter, connected sich auf den Webserver, auch via ftp, und lädt nach jedem durchgang eine html mit Statistik-Daten inkl Timestamp hoch. Auf diese "Website" greife ich dann im Alltag zu um das Ganze zu überwachen. Deshalb bin ich auf die Idee gekommen, im Falle von länger nicht aktualisieren Daten, per Aufruf eines Links, (der Einfachheit halber) das Skript neu starten zu lassen...

Klappt auch alles super bis auf den Aufruf des neu zu startenden Skripts

Nochmal zusammengefasst:
Skript A läuft auf Server und lädt Daten aus dem Netz herunter.
Nach jedem Durchgang wird zu Monitoring Zwecken eine HTML generiert und auf einen externen Webserver hochgeladen. Somit kann ich den aktuellen Stand im Alltag mit jedem Internetfähigen Gerät schnell mal überprüfen. Falls ich sehe dass seit zb 10 Minuten nichts mehr aktualisiert wurde, wird mit Aufruf einer php eine Datei auf dem Webserver erzeugt, auf welche Skript B reagieren soll.
Auf dem Server wo Skript A läuft, läuft auch Skript B, welches alle 30Sek überprüft ob auf dem besagten Webserver diese txt existiert. Wenn diese txt existiert sollen alle Konsolenfenster geschlossen werden, und das Skript A neu gestartet werden. Skript A sollte in einer Endlosschleife laufen, d. h. Skript B, welches weiterhin nach der txt ausschau halten soll, soll Skript A starten, und unabhängig von Skript A weiter in der Schleife laufen...
__deets__
User
Beiträge: 3693
Registriert: Mittwoch 14. Oktober 2015, 14:29

Samstag 9. Dezember 2017, 01:07

So richtig verstanden habe ich das noch nicht. Was haben denn Konsolenfenster damit zu tun? Die sind doch völlig unnötig für das laufen lassen eines Skripts.

Und so oder so ist doch jedes Kriterium, das du nach außen kommunizierst etwas, das du ja per Definition lokal bestimmt hast, auch geeignet Lokal alles wieder zu starten. Web, PHP, all das hat damit doch nix zu tun.
Sirius3
User
Beiträge: 8593
Registriert: Sonntag 21. Oktober 2012, 17:20

Samstag 9. Dezember 2017, 10:37

@Zeruat: auch wenn das Konstrukt sich reichlich kompliziert anhört, weil das Skript B auch einfach nach einer lokal abliegenden Datei schauen könnte und selbständig neustarten, hat Dein Programm auch sonst noch einige Probleme. Vergiß dass es soetwas wie `global` gibt, das löst keine Probleme sondern schafft nur viele andere; `global` auf Modulebene hat gar keine Wirkung. Es gibt Wahrheitswerte True und False, nutze die, statt eines Strings `'true'`. Da Du eine Endlosschleife willst, ist `run` auch überflüssig, weil es sich nie ändert. Funktionen haben Rückgabewerte, statt also ein globales `ftp` zu erzeugen, sollte `connectftp` einfach sein lokales `ftp` zurückgeben. Du ignorierst, dass die FTP-Verbindung zusammenbrechen könnte, oder sonst ein FTP-Fehler auftreten könnte; dann stürzt Dein Programm ab und Du hast kein Kontrollskript mehr laufen. Du importierst schon `subprocess`, benutzt es aber nicht. Damit kann man ganz einfach angeben, aus welchem Verzeichnis das Programm gestartet werden soll. Was ist der Sinn, `file_list` eine Liste mit einem leeren String als einziges Element zuzuweisen und es dann nicht zu benutzen? Wenn im else-Zweig nur pass steht, kann man ihn auch ganz weglassen. Wenn Du das Python-Programm beenden willst, warum beendest Du dann zwei völlig andere Programme?

Code: Alles auswählen

import time
import subprocess
from ftplib import FTP

RESTARTFILE = 'start.txt'

def connectftp():
    ftp = FTP('SERVER')
    ftp.login('USERNAME', 'PASSWORT')
    ftp.cwd('DOCUMENTROOT')
    return ftp


def check_restart():
    # TODO: Fehlerbehandlung
    ftp = connectftp()
    file_list = ftp.nlst()
    if RESTARTFILE in file_list:
        ftp.delete(RESTARTFILE)
        return True
    return False


def start_python():
    return subprocess.Popen(["python", "menu.py", "-autoload", "120", "new"],
        cwd="D:/Refactored")

def main():
    process = start_python()
    while True:
        time.sleep(30)
        if check_restart():
            process.kill()
            process = start_python()

if __name__ == '__main__':
    main()
Antworten