【发布时间】:2018-02-06 21:52:00
【问题描述】:
我尝试使用 Twisted 作为后端来允许用户使用 shell 命令搜索文件。
我遇到的问题是,当收到请求时,子进程会阻止新请求扭曲并将这些请求排队。这可以防止我取消之前的请求以运行新的请求。
我已经尝试了一些解决这个问题的方法,我发现这些解决方案包括 spawnprocess 和尝试使用 deferred。但是我无法找到返回输出的方法。任何帮助将不胜感激!
global child_pid
if child_pid is None:
pass
else:
for i in child_pid:
try:
i.kill()
except Exception as e:
pass
try:
find_cmd = ("find '/var/log/' -type f -name '*.log' -newermt '2018-
01-01 00:00:00' ! -newermt '2018-02-06 23:59:59' -exec cat {} \+ 2>&1")
# run search command
proc = subprocess.Popen(find_cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=True, preexec_fn=os.setsid)
# record pid of process so new requests can kill the previous
# subprocess
child_pid.append(proc)
# check for output until process is done
output = ''
while True:
line = proc.stdout.readline()
output += '\n' + line
if line == '' or proc.poll() is not None:
break
return output
except Exception as e:
return 'Error', False
编辑:
谢谢!我觉得我越来越近了。它不再阻塞了。不过我还是有点卡住了,我不知道为什么我花了这么长时间才弄清楚这一点……我读了这么多书,但我并没有陷入困境,我很沮丧,这可能没有帮助。
这是我目前所拥有的,可能会更好地了解我想要完成的工作:
from __future__ import print_function
from os import environ
from twisted.internet.protocol import ProcessProtocol
from twisted.internet import reactor
class Collector(ProcessProtocol):
def __init__(self):
self.output = ""
self.error = False
def connectionMade(self):
self.received = []
def childDataReceived(self, fd, data):
self.received.append(data)
def processExited(self, reason):
if 'code 0' in reason:
print('0')
self.error = False
else:
print('1')
self.error = True
reactor.stop()
def process_query(commands):
if len(commands) > 0:
return commands, 'success', True
return commands, 'fail', False
def run_shell_command(commands):
proto = Collector()
find = reactor.spawnProcess(
proto,
commands[0],
commands,
env=environ,
)
reactor.callLater(.5, find.signalProcess, b"KILL")
return proto.output, True
def format_output(output, commands):
output_list = []
try:
output_list = output.split('\n')
output_list.append(commands)
return ouptut_list, True
except:
return '', False
def run_command(commands):
response = {}
message = ''
result = True
# format and validate parameters
formatted_commands, message, result = process_query(commands)
# where result is pass or failure of the command and message is reason
if not result:
response['message'] = message
response['result'] = result
return response
shell_output, result = run_shell_command(formatted_commands)
# where result is pass or failure of the command
if not result:
response['message'] = 'Error'
return response
formatted_output, result = format_output(shell_output, formatted_commands)
response['data'] = formatted_output
response['result'] = result
if not result:
response['message'] = 'Error'
return response
if len(formatted_output) < 1:
response['message'] = 'No output found'
response['result'] = False
return response
return response
cmd = [b"find", b"/var/log",
b"-type", b"f",
b"-name", b"*.log",
b"-newermt", b"2018-01-01 00:00:00",
b"!", b"-newermt", b"2018-02-06 23:59:59",
b"-exec", b"cat", b"{}", b"+"]
x = run_command(cmd)
print(x)
reactor.run()
我一直在阅读有关延期的文章,他们似乎可以帮助我......可能是这样的:
def run_command(commands):
response = {}
message = ''
result = True
formatted_commands, message, result = process_query(commands)
if not result:
response['message'] = message
response['result'] = result
return response
shell_output = utils.getProcessOutput(formatted_commands)
shell_output.addCallback(format_output, formatted_commands)
response['data'] = shell_output
response['result'] = True
return response
这不起作用,但感觉很接近。我完全迷路了。感谢您到目前为止的帮助!
【问题讨论】:
-
我发布的答案的第一个版本(快速编辑)使用了 getProcessOutput。这是显而易见且简单的解决方案 - 除了您提到希望能够取消该进程,我将其读作“在完成之前杀死子进程”。如果你想要那样,不幸的是 getProcessOutput 没有帮助,因为它只给你结果,它没有给你任何杀死进程的方法。因此,使用自定义协议的 spawnProcess。杀死进程是一个重要的要求吗?
-
您应该在您的程序中启用日志记录,以便当 Twisted 为您捕获异常并记录它时,您可以实际看到它。这可能表明您的 processExited 存在错误(您无法检查字符串是否在
reason中)。此外,您似乎仍然没有正确使用 Deferreds。 Deferred 不是结果。它只是一个对象,您可以调用addCallback(f)以在某个时候调用f(the_result)。将您想要对结果执行的操作的逻辑放入一个函数中,并将其作为回调添加到 Deferred。