cherrypy выдает исключение, которое вызывает внутреннюю ошибку сервера при использовании блокировки вызовов gevent - PullRequest
3 голосов
/ 23 марта 2012

Я использую 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 не подойдет для цели использования гринлетов для блокировки вызовов ресурсов в запросах, и все равно не работает.

Есть предложения? Спасибо.

Ответы [ 2 ]

4 голосов
/ 11 октября 2012

Cherrypy использует threading.local для своих объектов request \ response (если это поддерживается вашей версией Python). Этот объект может быть исправлен для использования локального хранилища gevent с помощью gevent.monkey.patch_all. Просто используйте:

from gevent.monkey import patch_all
patch_all()

перед любым импортом (вы можете даже использовать обычную функцию "time" вместо gevent.time). Это исправлено здесь.

2 голосов
/ 24 марта 2012

CherryPy широко использует потоки и поэтому не предназначен для использования с циклами событий или другими подходами, которые обрабатывают несколько запросов в одном потоке.Может показаться, что какое-то время работает, если ваши тесты выполняют синхронные вызовы, но как только вы попробуете несколько одновременных запросов (которые приходят быстрее, чем обработчики могут вернуть ответы), вы столкнетесь с такого рода ошибкой.

Этодолжна быть возможность заменить cherrypy.serving на какой-то объект контекста, который предназначен для гринлетов или других параллелизмов, но на сегодняшний день никто не нашел времени для экспериментов.

...