首页 > 解决方案 > 如何使用实时日志记录和超时选项实现 subprocess.Popen?

问题描述

我的目标是实现一个支持运行系统命令(使用子进程)的 Python 3 方法,满足以下几个要求:

为了支持实时日志记录,我使用了 2 个线程来处理 stdout 和 stderr 输出。

我的挑战是强制线程和子进程进程超时。

我尝试使用信号处理程序实现超时,似乎在调用处理程序后立即冻结解释器。

我的实施有什么问题?

还有其他方法可以实现我的要求吗?

这是我当前的实现尝试:

def run_live_output(cmd, timeout=900, **kwargs):
    full_output = StringIO()

    def log_popen_pipe(p, log_errors=False):
        while p.poll() is None:
            output = ''
            if log_errors:
                output = p.stderr.readline()
                log.warning(f"{output}")
            else:
                output = p.stdout.readline()
                log.info(f"{output}")
            full_output.write(output)

        if p.poll():
            log.error(f"{cmd}\n{p.stderr.readline()}")

    class MyTimeout(Exception):
        pass

    def handler(signum, frame):
        log.info(f"Signal handler called with signal {signum}")
        raise MyTimeout

    with subprocess.Popen(
        cmd,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        stdin=subprocess.PIPE,
        universal_newlines=True, 
        **kwargs
    ) as sp:
        with ThreadPoolExecutor(2) as pool:
                try:
                    signal.signal(signal.SIGALRM, handler)
                    signal.alarm(timeout)
                    r1 = pool.submit(log_popen_pipe, sp)
                    r2 = pool.submit(log_popen_pipe, sp, log_errors=True)
                    r1.result()
                    r2.result()
                except MyTimeout:
                    log.info(f"Timed out - Killing the threads and process")
                    pool.shutdown(wait=True)
                    sp.kill()
                except Exception as e:
                    log.info(f"{e}")

    return full_output.getvalue()

标签: pythonpython-3.xsubprocesspython-multithreading

解决方案


推荐阅读