2015-11-19 5 views
5

Ich schreibe gerade mein erstes Python-Programm (in Python 2.6.6). Das Programm erleichtert das Starten und Stoppen verschiedener Anwendungen, die auf einem Server ausgeführt werden und dem Benutzer allgemeine Befehle bereitstellen (wie das Starten und Stoppen von Systemdiensten auf einem Linux-Server).Wie kann ich einen Prozess starten und in Python im Hintergrund anzeigen?

Ich beginne die Startskripten Anwendungen von

p = subprocess.Popen(startCommand, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
output, err = p.communicate() 
print(output) 

Das Problem ist, dass das Startskript von einer Anwendung im Vordergrund bleibt und so p.communicate() wartet für immer. Ich habe bereits versucht, "nohup startCommand &" vor dem startCommand zu verwenden, aber das hat nicht wie erwartet funktioniert.

Als Abhilfe verwende ich jetzt den folgenden Bash-Skript die Anwendung des Startskript zu nennen:

#!/bin/bash 

LOGFILE="/opt/scripts/bin/logs/SomeServerApplicationStart.log" 

nohup /opt/someDir/startSomeServerApplication.sh >${LOGFILE} 2>&1 & 

STARTUPOK=$(tail -1 ${LOGFILE} | grep "Server started in RUNNING mode" | wc -l) 
COUNTER=0 

while [ $STARTUPOK -ne 1 ] && [ $COUNTER -lt 100 ]; do 
    STARTUPOK=$(tail -1 logs/SomeServerApplicationStart.log | grep "Server started in RUNNING mode" | wc -l) 
    if ((STARTUPOK)); then 
     echo "STARTUP OK" 
     exit 0 
    fi 
    sleep 1 
    COUNTER=$(($COUNTER + 1)) 
done 

echo "STARTUP FAILED" 

Der Bash-Skript aus meinem Python-Code genannt wird. Diese Problemumgehung funktioniert perfekt, aber ich würde es vorziehen, alles in Python zu tun ...

Ist subprocess.Popen den falschen Weg? Wie kann ich meine Aufgabe nur in Python erledigen?

+1

wahrscheinlich eine dup von http://StackOverflow.com/Questions/1196074/start- a-background-process-in-python – daTokenizer

+0

Verwenden Sie einfach "kommunizieren", wenn es benötigt wird .. Sie müssen die Ergebnisse nicht überprüfen? vermeiden Sie es einfach ... – klashxx

+0

@Klashxx: Ich brauche die Ergebnisse. Das ist mein Problem ... (muss die Ausgabe überprüfen für "Server gestartet im RUNNING-Modus") – Ronzo

Antwort

1

Zuerst ist es einfach, das Python-Skript nicht zu blockieren, indem Sie ... kommunizieren, indem Sie nicht kommunizieren! Lesen Sie einfach von der Ausgabe oder der Fehlerausgabe des Befehls, bis Sie die richtige Nachricht gefunden haben und vergessen Sie den Befehl.

# to avoid waiting for an EOF on a pipe ... 
def getlines(fd): 
    line = bytearray() 
    c = None 
    while True: 
     c = fd.read(1) 
     if c is None: 
      return 
     line += c 
     if c == '\n': 
      yield str(line) 
      del line[:] 

p = subprocess.Popen(startCommand, shell=True, stdout=subprocess.PIPE, 
       stderr=subprocess.STDOUT) # send stderr to stdout, same as 2>&1 for bash 
for line in getlines(p.stdout): 
    if "Server started in RUNNING mode" in line: 
     print("STARTUP OK") 
     break 
else: # end of input without getting startup message 
    print("STARTUP FAILED") 
    p.poll() # get status from child to avoid a zombie 
    # other error processing 

Das Problem mit der oben ist, dass der Server noch ein Kind eines Python-Prozesses ist und unerwünschte Signale wie SIGHUP bekommen konnte. Wenn Sie einen Daemon erstellen möchten, müssen Sie zuerst einen Subprozess starten, der als nächstes Ihren Server startet. Auf diese Weise kann das erste Kind, wenn es beendet wird, vom Anrufer gewartet werden, und der Server erhält eine PPID von 1 (angenommen von init-Prozess). Sie können Multiprocessing-Modul verwenden, das Teil

-Code könnte zu erleichtern wie:

import multiprocessing 
import subprocess 

# to avoid waiting for an EOF on a pipe ... 
def getlines(fd): 
    line = bytearray() 
    c = None 
    while True: 
     c = fd.read(1) 
     if c is None: 
      return 
     line += c 
     if c == '\n': 
      yield str(line) 
      del line[:] 

def start_child(cmd): 
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, 
         shell=True) 
    for line in getlines(p.stdout): 
     print line 
     if "Server started in RUNNING mode" in line: 
      print "STARTUP OK" 
      break 
    else: 
     print "STARTUP FAILED" 

def main(): 
    # other stuff in program 
    p = multiprocessing.Process(target = start_child, args = (server_program,)) 
    p.start() 
    p.join() 
    print "DONE" 
    # other stuff in program 

# protect program startup for multiprocessing module 
if __name__ == '__main__': 
    main() 

Man könnte sich fragen, was die Notwendigkeit für den getlines Generator ist, wenn ein Datei-Objekt selbst ist ein Iterator, der eine Zeile in eine zurück Zeit. Das Problem ist, dass es intern read aufruft, die bis EOF lesen, wenn die Datei nicht mit einem Terminal verbunden ist. Da es jetzt mit einem PIPE verbunden ist, werden Sie nichts erhalten, bis der Server endet ... was ist nicht was erwartet wird

+0

Perfekt! Ich danke Ihnen sehr für Ihre Antwort. Jetzt weiß ich genau, wie es geht! – Ronzo

Verwandte Themen