FastCgi崩溃 -- 如何捕获所有异常?

0 投票
2 回答
2251 浏览
提问于 2025-04-15 11:29

我有一个在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 个回答

0

Broken pipe这个问题通常不是固定出现的。当你在一个管道或套接字上进行写操作时,如果另一端已经关闭了连接,就会出现Broken pipe的错误。所以,如果你的FastCGI遇到了Broken pipe,这意味着web服务器过早地关闭了连接。在某些情况下,这并不是一个大问题,可以悄悄忽略。

作为一个快速解决办法,可以尝试捕捉并忽略带有Broken pipesocket.error。你可能需要在很多地方添加一个except:的处理。

3

这可能是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的代码来捕捉这个错误。但我觉得这样做没有什么好处。特别是因为这个错误似乎并没有什么大碍,而且已经有补丁可以解决这个问题。

撰写回答