【问题标题】:cherrypy throws Exception which causes Internal Server Error when using blocking gevent calls使用阻塞 gevent 调用时,cherrypy 抛出异常,导致内部服务器错误
【发布时间】:2012-03-23 17:08:10
【问题描述】:

我正在使用 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 服务器将违背使用 greenlets 来阻止请求中的资源调用的目的,并且无论如何都不起作用。

有什么建议吗?谢谢。

【问题讨论】:

    标签: cherrypy gevent


    【解决方案1】:

    Cherrypy 将 threading.local 用于其请求\响应对象(如果您的 Python 版本支持)。可以使用 gevent.monkey.patch_all 修补此对象以使用 gevent 本地存储。只需使用:

    from gevent.monkey import patch_all
    patch_all()
    

    在任何导入之前(然后您甚至可以使用正常的“时间”函数而不是 gevent.time)。这在这里修复了它。

    【讨论】:

      【解决方案2】:

      CherryPy 广泛使用线程局部变量,因此不适合与事件循环或其他使用同一线程处理多个请求的方法一起使用。如果您的测试同步进行调用,它可能会工作一段时间,但是一旦您尝试多个同时请求(到达速度快于处理程序返回响应的速度),您就会遇到这种错误。

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

      【讨论】:

      • 啊,我明白了。有没有办法让服务器总是同步处理请求?因为整个并行化已经在请求级别以下实现。无论如何,感谢您的提示,我会尝试研究 cheryrpy.serving。如果我没有找到任何开关可以做到这一点,我会考虑使用另一个 Web 框架,或者实际上根本不使用,我只需要它来处理一种非常专业的请求,需要大量的处理能力。
      猜你喜欢
      • 2013-09-16
      • 1970-01-01
      • 1970-01-01
      • 2014-03-18
      • 2023-03-24
      • 2010-09-14
      • 1970-01-01
      • 2020-05-07
      • 2015-05-01
      相关资源
      最近更新 更多