Cherrypy throws Exception throwing backend server error when using gevent call blocking

I am using gevent wsgi to run cherry app and making some blocking gevent calls in request handlers. The blocking calls work as expected, successfully parallelizing the use of some blocking resources (pipes to other processes) if I make single requests. The problem occurs when I run multiple requests, then cherrypy returns an internal server error throwing this exception:

[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'

      

I've reduced the problem down to kernel and the following simple app reproduces the problem every time:

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()

      

To test it, I used the following script, which runs three requests at the same time:

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()

      

I'm not sure if I need to screw in the cherrypy or gevent (wsgi) library to find the bug. Setting spawn = None on the wsgi server will ignore the purpose of using green zones to block resource calls in requests and will not work anyway.

Any suggestions? Thank.

+3


source to share


2 answers


Cherrypy uses threading.local for its request \ response objects (if supported by your Python version). This object can be patched to use gevent local storage using gevent.monkey.patch_all. Just use:

from gevent.monkey import patch_all
patch_all()

      



before any import (then you can even use a regular "temporary" function instead of gevent.time). This is documented here.

+4


source


CherryPy uses threadlocals extensively and therefore is not intended to be used with event loops or other approaches that handle multiple requests with the same thread. It might work for a while if your tests are making calls synchronously, but once you try multiple simultaneous requests (which arrive faster than handlers can return responses), you run into this error.



It should be possible to replace cherrypy.serving

with some kind of context object that is intended for green or other concurrency, but to date nobody has found the time to experiment.

+2


source







All Articles