Назад | Перейти на главную страницу

Почему метод, использующий gevent в развернутом api Flask mod_wsgi, вызывает ошибку переключения потоков?

Я пытаюсь развернуть api Flask через Apache / mod_wsgi. API использует Gevent для обеспечения параллелизма для рекурсивного метода. Однако это вызывает следующую ошибку

[Mon Feb 08 12:05:37 2016] [error] error: cannot switch to a different thread
[Mon Feb 08 12:05:37 2016] [error] <callback at 0x1094ee350 args=()> failed with error

Весь api отлично работает с Gevent при запуске с использованием встроенного веб-сервера Pycharm, а api отлично работает с Apache / mod_wsgi, когда я не использую gevent для обеспечения параллелизма.

Я предполагаю, что это должно быть запущено в Apache, но мне пока не удалось найти решение. Я все время вижу упоминания об исправлении обезьян, поэтому я добавил эту строку в модуль, в котором вызывается gevent

from gevent import monkey; monkey.patch_all()

но, похоже, это не помогло.

Я нашел этот бит в автономных контейнерах WSGI в документации Flask (http://flask.pocoo.org/docs/0.10/deploying/wsgi-standalone/):

Gevent is a coroutine-based Python networking library that uses greenlet to provide a high-level synchronous API on top of libevent event loop:

from gevent.wsgi import WSGIServer
from yourapplication import app

http_server = WSGIServer(('', 5000), app)
http_server.serve_forever()

Также говорится, что

There are popular servers written in Python that contain WSGI applications and serve HTTP. These servers stand alone when they run; you can proxy to them from your web server. Note the section on Proxy Setups if you run into issues.

Нужно ли мне отказаться от использования mod_wsgi и использовать встроенный в Gevent сервер WSGI, а затем проксировать его через Apache? Это будет королевский PITA, особенно для решения проблем CORS (у нас есть веб-интерфейс, который обращается к api на том же сервере, и проксирование с другого порта вызовет множество проблем с перекрестным происхождением - если кто-то не убедит меня в обратном).

Мы будем очень благодарны за любое понимание того, что попробовать дальше.

apache mod_wsgi в настоящее время несовместим с gevent. Для эластичного beanstalk AWS с Apache я использовал async_mode = "threading" для Flask, и он хорошо работает. Обратите внимание, что многопоточность имеет меньшую производительность, чем gevent.
https://flask-socketio.readthedocs.io/en/latest/#deployment

app = Flask(__name__,static_folder='static')
socketio = SocketIO(app, async_mode="threading") 

Обратите внимание, что Flask может работать автономно с gevent.

app = Flask(__name__,static_folder='static')
socketio = SocketIO(app, async_mode="gevent") 

if __name__ == '__main__':
    HOST = '127.0.0.1'
    PORT = 5055
    socketio.run(app, port=PORT, host=HOST)

Однако вам действительно нужен HTTP-сервер перед ним, такой как Gunicorn.

Я нашел здесь ответ: Почему директива WSGIApplicationGroup% {GLOBAL} работает для создания новых потоков

В двух словах:

WSGIApplicationGroup: установите выполнение для того же интерпретатора Python (созданного первым).

Таким образом, по умолчанию каждый новый поток не должен использовать один и тот же экземпляр интерпретатора Python.

Для uWSGI эквивалентный метод - добавить это в ваш файл .ini:

single-interpreter = true

Я только что нашел здесь похожую тему https://stackoverflow.com/questions/9692089/why-gevent-on-a-flask-app-with-apache-mod-wsgi-is-raising-notimplementederror у этого есть решение.

Чтобы сделать то, что мне нужно, мне нужно добавить директиву WSGIApplicationGroup %{GLOBAL} в мой Apache conf. Мне тоже любопытно, почему это решает проблему.