FastCgi崩溃 -- 如何捕获所有异常?
我有一个在Apache上运行的Django应用,使用FastCGI(用的是Flup的WSGIServer)。
这个设置是通过dispatch.fcgi来完成的,下面是相关代码:
#!/usr/bin/python
import sys, os
sys.path.insert(0, os.path.realpath('/usr/local/django_src/django'))
PROJECT_PATH=os.environ['PROJECT_PATH']
sys.path.insert(0, PROJECT_PATH)
os.chdir(PROJECT_PATH)
os.environ['DJANGO_SETTINGS_MODULE'] = "settings"
from django.core.servers.fastcgi import runfastcgi
runfastcgi(method="threaded",daemonize='false',)
runfastcgi是执行工作的部分,最终会在WSGIHandler上运行一个WSGIServer。
有时候会发生异常,这会导致FastCGI崩溃。
编辑:我不知道是什么错误导致FastCGI崩溃,或者说FastCGI是否真的崩溃。我只知道有时候网站会一直无法访问,直到我重启Apache。错误日志中唯一出现的错误是“broken pipe”和“不完整的头部”,具体如下。
不完整的头部:
注意:我已经把敏感信息或杂乱内容替换成“...”了。
[Sat May 09 ...] [error] [client ...] (104)Connection reset by peer: FastCGI: comm with server ".../dispatch.fcgi" aborted: read failed
[Sat May 09 ...] [error] [client ...] FastCGI: incomplete headers (0 bytes) received from server ".../dispatch.fcgi"
[Sat May 09 ...] [error] [client ...] (32)Broken pipe: FastCGI: comm with server ".../dispatch.fcgi" aborted: write failed,
Broken pipe:
注意:这个是针对一个trac网站,而不是Django应用,但看起来是一样的。
Unhandled exception in thread started by <bound method Connection.run of <trac.web._fcgi.Connection object at 0xb53d7c0c>>
Traceback (most recent call last):
File "/usr/lib/python2.4/site-packages/Trac-0.12dev_r7715-py2.4.egg/trac/web/_fcgi.py", line 654, in run
self.process_input()
File "/usr/lib/python2.4/site-packages/Trac-0.12dev_r7715-py2.4.egg/trac/web/_fcgi.py", line 690, in process_input
self._do_params(rec)
File "/usr/lib/python2.4/site-packages/Trac-0.12dev_r7715-py2.4.egg/trac/web/_fcgi.py", line 789, in _do_params
self._start_request(req)
File "/usr/lib/python2.4/site-packages/Trac-0.12dev_r7715-py2.4.egg/trac/web/_fcgi.py", line 773, in _start_request
req.run()
File "/usr/lib/python2.4/site-packages/Trac-0.12dev_r7715-py2.4.egg/trac/web/_fcgi.py", line 582, in run
self._flush()
File "/usr/lib/python2.4/site-packages/Trac-0.12dev_r7715-py2.4.egg/trac/web/_fcgi.py", line 589, in _flush
self.stdout.close()
File "/usr/lib/python2.4/site-packages/Trac-0.12dev_r7715-py2.4.egg/trac/web/_fcgi.py", line 348, in close
self._conn.writeRecord(rec)
File "/usr/lib/python2.4/site-packages/Trac-0.12dev_r7715-py2.4.egg/trac/web/_fcgi.py", line 705, in writeRecord
rec.write(self._sock)
File "/usr/lib/python2.4/site-packages/Trac-0.12dev_r7715-py2.4.egg/trac/web/_fcgi.py", line 542, in write
self._sendall(sock, header)
File "/usr/lib/python2.4/site-packages/Trac-0.12dev_r7715-py2.4.egg/trac/web/_fcgi.py", line 520, in _sendall
sent = sock.send(data)
socket.error: (32, 'Broken pipe')
我查看了/var/log/apache2/error.log,但似乎找不到崩溃的原因。我有时候会遇到内存交换的问题,但我觉得这可能是不同的情况。(请原谅我的无知。我愿意学习如何更好地实施和调试服务器管理的内容。)
我想用try/except来包裹runfastcgi。处理随机异常的最佳方法是什么(在我找到实际原因之前)?
我相信WSGIServer可以处理很多请求。如果我捕获到一个异常,能否在不担心进入无限循环的情况下重新调用runfastcgi?我是否应该为引发异常的请求返回一个错误的HttpRequest?我甚至不太确定该怎么做。
我一直在查看django/core/servers/fastcgi.py、django/core/handlers/wsgi.py和django/http/init.py。
我还没有能理解Flup那边的内容。
有没有什么想法或经验可以分享给我学习的?
谢谢!
2 个回答
Broken pipe这个问题通常不是固定出现的。当你在一个管道或套接字上进行写操作时,如果另一端已经关闭了连接,就会出现Broken pipe的错误。所以,如果你的FastCGI遇到了Broken pipe,这意味着web服务器过早地关闭了连接。在某些情况下,这并不是一个大问题,可以悄悄忽略。
作为一个快速解决办法,可以尝试捕捉并忽略带有Broken pipe
的socket.error
。你可能需要在很多地方添加一个except:
的处理。
这可能是Flup的一个bug。当一个基于Flup的服务器的客户端连接在Flup还没发送完数据的时候就关闭了,就会出现一个叫做socket.error: (32, 'Broken pipe')的错误。
试图在runfastcgi周围用try catch来捕捉这个错误是行不通的。原因很简单,因为这个错误是在一个不同的线程中产生的。
好吧,我来解释一下为什么用try catch包裹自己的代码是没用的。如果你仔细看一下错误的追踪信息,你会发现追踪的第一行并不是runfastcgi。这是因为错误发生在另一个线程里。如果你想捕捉这个错误,你需要把追踪信息中列出的任何语句用try/catch包裹起来,像这样:
# in file /usr/lib/python2.4/site-packages/Trac-0.12dev_r7715-py2.4.egg/trac/web/_fcgi.py", line 654, in run
try:
self.process_input()
except socket.error:
# ignore or print an error
pass
关键是,你可以通过修改Flup的代码来捕捉这个错误。但我觉得这样做没有什么好处。特别是因为这个错误似乎并没有什么大碍,而且已经有补丁可以解决这个问题。