Python 筛选具有潜在未安装输出的进程输出,检测退出代码和X之后的超时
我有一些现有的Django代码在uwsgi(在Linux下)下运行,禁用了线程功能,它为一些请求执行一个我无法控制的子进程 正常操作如下:Python 筛选具有潜在未安装输出的进程输出,检测退出代码和X之后的超时,python,django,subprocess,uwsgi,Python,Django,Subprocess,Uwsgi,我有一些现有的Django代码在uwsgi(在Linux下)下运行,禁用了线程功能,它为一些请求执行一个我无法控制的子进程 正常操作如下: 子流程运行的时间很短,并返回退出代码0或其他内容。代码将向stdout/stderr写入一些消息。返回代码(退出代码)将告诉我工作是否正确完成。如果执行失败,最好收集stdout/stderr并记录它,以了解失败的原因 然而,在极少数情况下,子流程可能会遇到迄今为止尚未理解的竞争条件,并将执行以下操作 它将反复向stdout和stderr写入特定消息,
- 子流程运行的时间很短,并返回退出代码0或其他内容。代码将向stdout/stderr写入一些消息。返回代码(退出代码)将告诉我工作是否正确完成。如果执行失败,最好收集stdout/stderr并记录它,以了解失败的原因
- 它将反复向stdout和stderr写入特定消息,并循环并永久挂起
import os
import select
import subprocess
import time
CMD = ["bash", "-c", "echo hello"]
def run_proc(cmd=CMD, timeout=10):
""" run a subprocess, fetch (and analyze stdout / stderr) and
detect if script runs too long
and exit when script finished
"""
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout = proc.stdout.fileno()
stderr = proc.stderr.fileno()
t0 = time.time()
while True:
if time.time() - t0 > timeout:
print("TIMEOUT")
break
rc = proc.returncode
print("RC", rc)
if proc.returncode is not None:
break
to_rd, to_wr, to_x = select.select([stdout, stderr], [], [], 2)
print(to_rd, to_wr, to_x)
if to_rd:
if stdout in to_rd:
rdata = os.read(stdout, 100)
print("S:", repr(rdata))
if stderr in to_rd:
edata = os.read(stderr, 100)
print("E:", repr(edata))
print(proc.returncode)
事实上,我不需要分别处理stdout和stderr,但这并没有改变任何事情
然而,当子流程完成其输出时,发生了一些非常奇怪的事情
the output of select tells me, that stdout and stderr can be read from, but when I read I get an empty string.
proc.returncode is still None
如何修复上述代码,或者如何以不同的方式保存问题?请至少检查:
输出:
非常感谢。
proc.poll()
对我有帮助。但是while proc.poll()是None,proc.returncode是None:
我想可以改成while proc.poll():
或者改成while True:
后面跟着rc=proc.poll()
,如果rc不是None,则在某个地方出现一个:break
另一个问题。proc.terminate()
似乎会留下一个僵尸。任何避免这种情况的方法。由于uwsgi运行了很长一段时间,理论上有可能会留下相当多的僵尸proc.terminate()
,然后是proc.wait()
似乎解决了僵尸问题。我已经给出了您的答案。请调整您的答案,以便调用proc.terminate()
和proc.wait()
,或者更改while语句,使proc.poll()的结果更清楚
是proc.returncode
或者如果您愿意,我可以将这些更改添加到您的答案中,然后将此答案标记为solution@gelonida:请编辑我的答案。
def run_proc(cmd=CMD, timeout=10):
""" run a subprocess, fetch (and analyze stdout / stderr) and
detect if script runs too long
and exit when script finished
"""
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout = proc.stdout.fileno()
stderr = proc.stderr.fileno()
t0 = time.time()
while True:
returncode = proc.poll()
print("RC", returnode)
if returncode is not None:
break
if time.time() - t0 > timeout:
print("TIMEOUT")
# You need to kill the subprocess, break doesn't stop it!
proc.terminate()
# wait for the killed process to 'reap' the zombie
proc.wait()
break
to_rd, to_wr, to_x = select.select([stdout, stderr], [], [], 2)
print(to_rd, to_wr, to_x)
if to_rd:
if stdout in to_rd:
rdata = os.read(stdout, 100)
print("S:", repr(rdata))
if stderr in to_rd:
edata = os.read(stderr, 100)
print("E:", repr(edata))
print(returncode)
RC None
[3] [] []
S: b'hello\n'
RC None
[3, 5] [] []
S: b''
E: b''
0