如何监控一个“卡住”的Python脚本?

0 投票
4 回答
5873 浏览
提问于 2025-04-16 06:32

我有一个数据处理量很大的Python脚本,它通过HTTP连接下载数据。我通常是在晚上运行这个脚本。有时候连接会失败,或者某个网站暂时无法访问。我有一些基本的错误处理机制,可以捕捉这些异常,并定期重试,如果重试5分钟后还不行,就会优雅地退出(并记录错误)。

不过,我发现有时候这个任务会卡住。没有抛出错误,任务仍在运行,有时在最后一次打印信息后几个小时都没有任何反应。

那么,最好的方法是什么呢:

  • 监控一个Python脚本,
  • 检测它在给定时间后是否无响应,
  • 如果无响应就退出它,
  • 启动另一个脚本?

更新

感谢大家的帮助。正如你们中的一些人指出的,urllibsocket模块没有正确设置超时。我正在使用Python 2.5,并且使用了Freebaseurllib2模块,捕捉和处理MetawebErrorsurllib2.URLErrors。这是在最后一个脚本挂起12小时后的错误输出示例:

  File "/home/matthew/dev/projects/myapp_module/project/app/myapp/contrib/freebase/api/session.py", line 369, in _httpreq_json
    resp, body = self._httpreq(*args, **kws)
  File "/home/matthew/dev/projects/myapp_module/project/app/myapp/contrib/freebase/api/session.py", line 355, in _httpreq
    return self._http_request(url, method, body, headers)
  File "/home/matthew/dev/projects/myapp_module/project/app/myapp/contrib/freebase/api/httpclients.py", line 33, in __call__
    resp = self.opener.open(req)
  File "/usr/lib/python2.5/urllib2.py", line 381, in open
    response = self._open(req, data)
  File "/usr/lib/python2.5/urllib2.py", line 399, in _open
    '_open', req)
  File "/usr/lib/python2.5/urllib2.py", line 360, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.5/urllib2.py", line 1107, in http_open
    return self.do_open(httplib.HTTPConnection, req)
  File "/usr/lib/python2.5/urllib2.py", line 1080, in do_open
    r = h.getresponse()
  File "/usr/lib/python2.5/httplib.py", line 928, in getresponse
    response.begin()
  File "/usr/lib/python2.5/httplib.py", line 385, in begin
    version, status, reason = self._read_status()
  File "/usr/lib/python2.5/httplib.py", line 343, in _read_status
    line = self.fp.readline()
  File "/usr/lib/python2.5/socket.py", line 372, in readline
    data = recv(1)
KeyboardInterrupt

你会注意到底部的socket错误。由于我使用的是Python 2.5,而且没有访问第三个urllib2.urlopen选项的权限,还有其他方法可以监控和捕捉这个错误吗?比如,我正在捕捉URLErrors,在urllib2socket中还有其他类型的错误可以捕捉吗,这样能帮到我吗?

4 个回答

1

你可以在 pdb 这个工具里运行你的脚本,当你觉得它卡住的时候就可以暂停。这个方法本身不能解决问题,但可能会帮助你找出为什么它会卡住的原因。

7

听起来你的脚本里有个错误。解决办法不是去监视这个错误,而是要找到它并修复。

我们无法帮你找到错误,因为需要看到一些代码。不过一般来说,你可以使用日志记录来确定问题出现的地方,并编写单元测试,这样可以让你更有信心,知道哪些代码部分没有错误。

另一个建议是用 Ctrl-C 中断你“卡住”的程序,然后查看错误追踪信息。这个信息会告诉你程序最后执行到哪一行。这样可能会给你一些关于脚本出错的线索。

4

因为这个程序是在进行网络通信,所以我建议你使用一个调试代理工具,比如 Charles http://www.charlesproxy.com/,看看你的脚本和服务器之间的交流有没有什么奇怪的地方。

另外要注意,socket模块默认是没有设置超时的,这样可能会导致程序卡住。不过从Python 2.6开始,你可以在使用urllib2.urlopen时传入第三个参数,指定请求的超时时间(单位是秒)。这样的话,如果服务器不响应,脚本就会报错,而不是一直等待下去。如果你还没检查过这些,建议先看看这些内容,再进行更复杂的操作。

关于Python 2.5的更新: 在Python 2.6之前,你需要直接在urllib2使用的socket模块中设置超时值。我没有尝试过这个,但应该是可行的。这个信息我是在 http://www.voidspace.org.uk/python/articles/urllib2.shtml 找到的:

import socket
import urllib2

# timeout in seconds
timeout = 10
socket.setdefaulttimeout(timeout)

# this call to urllib2.urlopen now uses the default timeout
# we have set in the socket module
req = urllib2.Request('http://www.voidspace.org.uk')
response = urllib2.urlopen(req)

撰写回答