cherrypy throws使用阻塞gevent调用时导致内部服务器错误的异常

时间:2012-03-23 17:08:11

标签: cherrypy gevent

我正在使用gevent wsgi运行一个cherrypy应用程序,并在请求程序中执行一些阻止gevent调用。如果我发出单个请求,阻塞调用会按预期成功并行地使用某些阻塞资源(管道到其他进程)。当我触发多个请求时出现问题,然后cherrypy返回抛出此异常的内部服务器错误:

[23/Mar/2012:17:50:35]  Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/CherryPy-3.2.2-py2.7.egg/cherrypy/_cpwsgi.py", line 170, in trap
return func(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/CherryPy-3.2.2-py2.7.egg/cherrypy/_cpwsgi.py", line 97, in __call__
return self.nextapp(environ, start_response)
  File "/usr/local/lib/python2.7/site-packages/CherryPy-3.2.2-py2.7.egg/cherrypy/_cpwsgi.py", line 385, in tail
return self.response_class(environ, start_response, self.cpapp)
  File "/usr/local/lib/python2.7/site-packages/CherryPy-3.2.2-py2.7.egg/cherrypy/_cpwsgi.py", line 232, in __init__
outstatus = r.output_status
AttributeError: 'Response' object has no attribute 'output_status'

我将问题缩减到核心,以下简单的应用程序每次都会重现问题:

import cherrypy
import gevent
from gevent import wsgi

class BugServer(object):
    @cherrypy.expose
    def index(self):
      gevent.sleep(2)
      return 'dummy foo'

if __name__ == "__main__":
        app = cherrypy.tree.mount(BugServer(), '/')
        wsgi.WSGIServer(('', 27726), app).serve_forever()

为了测试它,我使用了以下脚本同时触发三个请求:

import httplib
import threading

def make_req(host):
        conn = httplib.HTTPConnection(host)
        conn.request("GET", "/")
        return conn.getresponse()

threads = []
for i in range(3):
        t = threading.Thread(target=make_req, args=('192.168.128.7:27726',), kwargs={})
        t.start()
        threads.append(t)

for t in threads:
        t.join()

我不确定是否需要深入了解cherrypy或gevent(wsgi)库来查找错误。将spawn = None设置为wsgi服务器将违反使用greenlet阻止请求中的资源调用的目的,并且无论如何都不起作用。

有什么建议吗?感谢。

2 个答案:

答案 0 :(得分:4)

Cherrypy使用threading.local作为其request \ response对象(如果Python版本支持它)。可以使用gevent.monkey.patch_all修补此对象以使用gevent本地存储。只需使用:

from gevent.monkey import patch_all
patch_all()

在任何导入之前(你甚至可以使用普通的“时间”函数而不是gevent.time)。这修好了。

答案 1 :(得分:2)

CherryPy广泛使用threadlocals,因此不适用于事件循环或使用相同线程处理多个请求的其他方法。如果您的测试同步进行调用,它可能会工作一段时间,但只要您尝试多个同时发出的请求(比处理程序可以返回响应的速度快到达),您将遇到此类错误。

应该可以将cherrypy.serving替换为专为greenlet或其他并行设计的某种上下文对象,但到目前为止,没有人花时间进行实验。