PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : python3 subprocess wird nicht beendet



Huhn Hur Tu
29.12.16, 11:04
Hi,

wieder mal ein bloedes Python Problem



subprocess.Popen([sftp_path, '-i', ssh_id_key, sftp_connect + ':/files/om_db_output_' + YesterDayDate, tmp_path + '/om_db_output.log'])




In [22]: subprocess.Popen([sftp_path, '-i', ssh_id_key, sftp_connect + ':/files/om_db_output_' + YesterDayDate, tmp_path + '/om_db_output.log'])
Out[22]: <subprocess.Popen at 0x7f54e7172630>

In [23]: Connected to TARGETSERVER.
Fetching /files/om_db_output_2016-12-28 to /opt/ui/data/montool/tool_tmp/soccer_oms/om_db_output.log
/files/om_db_output_2016-12-28 100% 396KB 395.6KB/s 00:00
^C
KeyboardInterrupt


Der subprocess holt die Datei und schreibt diese erfolgreich Lokal, aber dann wird der nicht beendet, das Beispiel ist aus "ipython3"

Gruss Stefan

nopes
29.12.16, 11:46
Nun ich denke du hast mehrere Optionen, zum einen kannst du subprocess.run (https://docs.python.org/3/library/subprocess.html#using-the-subprocess-module) verwenden, dem kann man sagen, dass der Befehl so und so schnell beendet werden muss

subprocess.Popen([sftp_path, '-i', ssh_id_key, sftp_connect + ':/files/om_db_output_' + YesterDayDate, tmp_path + '/om_db_output.log'], timeout=5)

The timeout argument is passed to Popen.communicate() (https://docs.python.org/3/library/subprocess.html#subprocess.Popen.communicate). If the timeout expires, the child process will be killed and waited for. The TimeoutExpired exception will be re-raised after the child process has terminated.

Die anderen sind, wie da ja auch steht, subprocess.Popen.communicate (https://docs.python.org/3/library/subprocess.html#subprocess.Popen.communicate) zu verwenden, alternative ginge auch subprocess.Popen.wait (https://docs.python.org/3/library/subprocess.html#subprocess.Popen.wait).

Oder du nutzt subprocess.Popen.poll (https://docs.python.org/3/library/subprocess.html#subprocess.Popen.poll) und implementierst das mit dem Timeout selber. So oder so, musst du halt sicherstellen, was mit dem Prozess los ist und ob er in endlicher Zeit seine Aufgabe erfüllt halt, zB etwa so:


"""
The child process is not killed if the timeout expires, so in order to cleanup properly a well-behaved application should kill the child process and finish communication:
"""
proc = subprocess.Popen([sftp_path, '-i', ssh_id_key, sftp_connect + ':/files/om_db_output_' + YesterDayDate, tmp_path + '/om_db_output.log'])
try:
outs, errs = proc.communicate(timeout=180)
except TimeoutExpired:
proc.kill()
outs, errs = proc.communicate()

Huhn Hur Tu
29.12.16, 12:02
Gefunden, nachdem ich statt Popen call verwendet habe, wurder der subprocess beendet, wobei ich gerade nicht verstehe warum

nopes
29.12.16, 12:10
Das ist relativ einfach zu erklären.
Blick auf die Doku zu subprocess.call (https://docs.python.org/3/library/subprocess.html#subprocess.call):


Run the command described by args. Wait for command to complete, then return the returncode attribute.

This is equivalent to:


run(...).returncode
(except that the input and check parameters are not supported)
Ok, sehen wir uns als mal subprocess.run (https://docs.python.org/3/library/subprocess.html#subprocess.run) an:

Run the command described by args. Wait for command to complete, then return a CompletedProcess instance.
...
Das Problem ist, wenn der Befehl kein Ende findet, hast du ein Deadlock erzeugt, diese Option will man aber eigentlich nie haben, also solltest du ein Timeout vorgeben, so dass dein Programm nicht versehentlich stecken bleiben kann.


[edit]Oder um es klar zu sagen, in deinem "ersten Versuch" hast du Sig Term an den Hauptprozess geschickt, der hat es aber nicht an den Sub Process weitergereicht, das wurde gemeldet. Sauberst Lösung für diese Art von Problem sind eigene Signal Hanlder - https://docs.python.org/3/library/signal.html#example
Aber obacht, macht den Code schnell ziemlich schwierig...