【问题标题】:How to launch crashing (rarely) application in subprocess如何在子进程中启动崩溃(很少)应用程序
【发布时间】:2012-12-06 13:58:44
【问题描述】:

我有一个 python 应用程序,它需要每天执行大约 20000 次专有应用程序(有时会崩溃)。

问题是当应用程序崩溃时,Windows 会自动触发WerFault,这将使程序挂起,因此python's subprocess.call() 将永远等待用户输入(该应用程序必须在周末、节假日、24/7 运行...所以这是不可接受的)。

如果虽然要使用sleep; poll; kill; terminate但那将意味着失去使用communicate()的能力,应用程序可以运行从几毫秒到2小时,因此设置固定超时将无效

我也尝试过turning on automatic debugging(使用一个脚本,该脚本会获取应用程序的崩溃转储并终止 id),但不知何故,这个 howto 在我的服务器上不起作用(WerFault 仍然出现并且等待用户输入)。

this 等其他几个教程也没有任何效果。

问题: 有没有办法防止 WerFault 显示(等待用户输入)? 这是比编程问题更系统的问题

另类问题:python中是否有一种优雅的方式来检测应用程序崩溃(是否显示WerFault

【问题讨论】:

标签: windows python-3.x crash subprocess


【解决方案1】:

我看不出你的程序为什么需要崩溃,找到有问题的代码,并将其放入 try 语句中。

http://docs.python.org/3.2/tutorial/errors.html#handling-exceptions

【讨论】:

  • 问题在于专有应用程序崩溃。我们对此无能为力(支持不佳):(
  • 应用程序崩溃。这是生活中的事实。即使它是您的应用程序并且您可以修复崩溃,处理崩溃通常也很有意义。在这种情况下,它是无法修复的第 3 方应用程序。
【解决方案2】:

简单(且丑陋)的答案,不时监视WerFault.exe 实例,特别是与违规应用程序的PID 关联的实例。并杀死它。处理WerFault.exe 很复杂,但您不想禁用它——请参阅Windows Error Reporting 服务。

  1. 按名称获取与WerFault.exe 匹配的进程列表。我使用psutil 包。请注意psutil,因为进程已缓存,请使用psutil.get_pid_list()
  2. 使用argparse 对其命令行进行解码。这可能有点矫枉过正,但它利用了现有的 python 库。
  3. 根据PID 识别持有您的应用程序的进程。

这是一个简单的实现。

def kill_proc_kidnapper(self, child_pid, kidnapper_name='WerFault.exe'):
    """
    Look among all instances of 'WerFault.exe' process for an specific one
    that took control of another faulting process.
    When 'WerFault.exe' is launched it is specified the PID using -p argument:

    'C:\\Windows\\SysWOW64\\WerFault.exe -u -p 5012 -s 68'
                             |               |
                             +-> kidnapper   +-> child_pid

    Function uses `argparse` to properly decode process command line and get
    PID. If PID matches `child_pid` then we have found the correct parent
    process and can kill it.
    """
    parser = argparse.ArgumentParser()
    parser.add_argument('-u', action='store_false', help='User name')
    parser.add_argument('-p', type=int, help='Process ID')
    parser.add_argument('-s', help='??')

    kidnapper_p = None
    child_p = None

    for proc in psutil.get_pid_list():
        if kidnapper_name in proc.name:
            args, unknown_args = parser.parse_known_args(proc.cmdline)
            print proc.name, proc.cmdline

            if args.p == child_pid:
                # We found the kidnapper, aim.
                print 'kidnapper found: {0}'.format(proc.pid)
                kidnapper_p = proc

    if psutil.pid_exists(child_pid):
        child_p = psutil.Process(child_pid)

    if kidnapper_p and child_pid:
        print 'Killing "{0}" ({1}) that kidnapped "{2}" ({3})'.format(
            kidnapper_p.name, kidnapper_p.pid, child_p.name, child_p.pid)
        self.taskkill(kidnapper_p.pid)
        return 1
    else:
        if not kidnapper_p:
            print 'Kidnapper process "{0}" not found'.format(kidnapper_name)
        if not child_p:
            print 'Child process "({0})" not found'.format(child_pid)

    return 0

现在,taskkill 函数使用正确的 PID 调用 taskkill 命令。

def taskkill(self, pid):
    """
    Kill task and entire process tree for this process
    """
    print('Task kill for PID {0}'.format(pid))
    cmd = 'taskkill /f /t /pid {0}'.format(pid)
    subprocess.call(cmd.split())

【讨论】:

  • 非常好的第一个答案 :) 我基本上已经在做类似的事情了,但是我没有杀死进程,而是通过 nagios 通知管理员,以便他们可以创建故障转储。
猜你喜欢
  • 2016-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多