Привет,
Я вижу эту ошибку с Gunicorn 19.x
(проверено с 19.0
и 19.1.1
) с использованием рабочего gevent
. Я использую django-1.7.1
.
это исключение:
Traceback:
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
87. response = middleware_method(request)
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/contrib/auth/middleware.py" in process_request
34. if user and hasattr(user, 'get_session_auth_hash'):
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/utils/functional.py" in inner
224. self._setup()
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/utils/functional.py" in _setup
357. self._wrapped = self._setupfunc()
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/contrib/auth/middleware.py" in <lambda>
23. request.user = SimpleLazyObject(lambda: get_user(request))
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/contrib/auth/middleware.py" in get_user
11. request._cached_user = auth.get_user(request)
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/contrib/auth/__init__.py" in get_user
151. user_id = request.session[SESSION_KEY]
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/contrib/sessions/backends/base.py" in __getitem__
49. return self._session[key]
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/contrib/sessions/backends/base.py" in _get_session
175. self._session_cache = self.load()
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/contrib/sessions/backends/db.py" in load
21. expire_date__gt=timezone.now()
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/models/manager.py" in manager_method
92. return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/models/query.py" in get
351. num = len(clone)
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/models/query.py" in __len__
122. self._fetch_all()
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/models/query.py" in _fetch_all
966. self._result_cache = list(self.iterator())
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/models/query.py" in iterator
265. for row in compiler.results_iter():
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in results_iter
700. for rows in self.execute_sql(MULTI):
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in execute_sql
784. cursor = self.connection.cursor()
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/backends/__init__.py" in cursor
163. self.validate_thread_sharing()
File "/home/sieve/sitroom.sieve.com.br/shared/env/local/lib/python2.7/site-packages/django/db/backends/__init__.py" in validate_thread_sharing
515. % (self.alias, self._thread_ident, thread.get_ident()))
Exception Type: DatabaseError at /
Exception Value: DatabaseWrapper objects created in a thread can only be used in that same thread. The object with alias 'default' was created in thread id 140049505195808 and this is thread id 61130224.
Вот мой gunicorn.conf.py
:
##
# Gunicorn config at
# Managed by Chef - Local Changes will be Nuked from Orbit (just to be sure)
##
# What ports/sockets to listen on, and what options for them.
bind = "127.0.0.1:9300"
# The maximum number of pending connections
backlog = 2048
# What the timeout for killing busy workers is, in seconds
timeout = 300
# How long to wait for requests on a Keep-Alive connection, in seconds
keepalive = 2
# The maxium number of requests a worker will process before restarting
max_requests = 1024
# Whether the app should be pre-loaded
preload_app = True
# How many worker processes
workers = 16
# Type of worker to use
worker_class = "gevent"
# The granularity of error log outputs.
loglevel = "error"
Ошибка возникает каждый раз, простой доступ к любому URL-адресу приложения django (который, конечно, зависит от любой модели) вызывает эту ошибку. Любые идеи?
Поскольку переход на gunicorn-18.0
решает проблему, я предполагаю, что gunicorn-19.x
делает что-то другое.
Если вам нужна дополнительная информация, дайте мне знать, и я размещу ее здесь.
На данный момент я использую 18.0
.
Большое спасибо.
Сначала просто вопрос: помогает ли отключение опции предварительной нагрузки?
Думаю, я помню, как сообщалось об еще одной подобной проблеме.
Если изменение этой опции помогает, значит, мы должны что-то изменить в способе загрузки приложений Django, и нам будет легче отследить это.
Я _ думаю_, что мы импортируем приложение django wsgi в главный процесс, который, по крайней мере, на django 1.7, инициализирует все модели django при импорте.
Привет, @tilgovi , спасибо за preload_app = False
я могу использовать gunicorn-19.1.1
и django-1.7.1
.
Вы хоть представляете, что облако-пулеметчик по-другому делает с этим в версиях 19.x
?
У меня теперь вторая проблема. Я использую Raven [1] в своем приложении django. И согласно документации Raven, при использовании промежуточного программного обеспечения WSGU [1] можно использовать Raven как объект WSGI (обертывание исходного приложения django WSGI), а при использовании gunicorn (как внешняя команда, а не run_gunicorn
django command) мы должны добавить ловушку к gunicorn [2]. Когда этот перехватчик включен, gunicorn загружается, только если preload_app = True
, но тогда gevent не работает. Когда я использую preload_app = True
с включенным перехватчиком, gunicorn даже не загружается, что дает мне и ImportError
говоря, что он не может импортировать мой "DJANGO_SETTINGS_MODULE".
Ворон - 4.2.3
А пока я вернусь к gunicorn 18.x
, поскольку он работает с обеими конфигурациями (gevent и raven как промежуточное ПО WSGI).
Следует ли мне открыть еще один вопрос по этому поводу?
[1] http://raven.readthedocs.org/en/latest/config/django.html#wsgi -middleware
[2] http://raven.readthedocs.org/en/latest/config/django.html#gunicorn
@daltonmatos способ настройки баз данных в django 1.7.1, вероятно, изменился, по-видимому, не является потокобезопасным. Я не знаю, что делать в этот момент.
Еще одна вещь, которую я узнал сегодня,
обработка сеанса в django 1.7 с Gunicorn 19.3.0 истекает через секунды.
Пришлось вернуться к 18, чтобы все заработало.
К вашему сведению.
Похоже, это та же проблема, что и https://github.com/benoitc/gunicorn/issues/879 , который был закрыт, но не исправлен. Это делает Gunicorn 19.x. невозможно использовать с Django. Возможно, только для работника gevent? Я не тестировал другие типы рабочих.
@tilgovi Интересно, не связано ли это с изменениями, wsgi.multithread
в true
где это было false
в 18.x:
https://github.com/benoitc/gunicorn/blob/master/gunicorn/workers/ggevent.py#L99
Это изменение может обрабатываться в django по-другому. А гринлет - это не совсем нить. Мысли? По крайней мере, возможно, мы могли бы попытаться вернуть его и проверить, решает ли он проблему. Есть ли у нас тест или воспроизводимый способ решения этой проблемы?
О, я уверен, что проблема в этом. Доброй памяти, @benoitc.
Я до сих пор не знаю почему. Как я сказал в то время, чтобы оправдать это изменение, я не могу себе представить, что это приведет к поломке чего-либо, потому что это будет означать, что фреймворк будет принимать только дополнительные меры предосторожности при совместном использовании данных. Видимо, могу ошибаться.
Я нажал ветку fix/927
чтобы проверить, работает ли вышеуказанное исправление. Пожалуйста, протестируйте!
Я все еще могу воспроизвести эту ошибку, используя fix / 927 с django 1.8.1 (и 1.7.1) и gevent 1.0.1
Это меня обнадеживает, даже если мы до сих пор не знаем причины.
Поэтому я попытался использовать пример приложения и не воспроизвел проблему, выполнив следующую командную строку:
gunicorn --env DJANGO_SETTINGS_MODULE=testing.settings -k gevent -w3 wsgi:application
Может ли кто-нибудь дать мне воспроизводимый пример?
Я все еще могу воспроизвести эту проблему, вызывая Gunicorn следующим образом:
gunicorn --env DJANGO_SETTINGS_MODULE=settings -w 3 --max-requests=1000 -b 0.0.0.0:8000 -k gevent --config ogs/gunicorn.py --pythonpath ogs wsgi:application
Есть ли какие-нибудь подробности, которые вам нужны?
@brockhaywood должен быть project.settings
, но да, мне нужен способ воспроизвести его, есть ли у вас какой-нибудь минимальный код, которым можно поделиться.
Глядя на след выше, это также может быть исправление обезьяны. Может быть, темы не следует исправлять обезьянами. Можете попробовать следующий патч?
--- a/gunicorn/workers/ggevent.py
+++ b/gunicorn/workers/ggevent.py
@@ -60,9 +60,9 @@ class GeventWorker(AsyncWorker):
# if the new version is used make sure to patch subprocess
if gevent.version_info[0] == 0:
- monkey.patch_all()
+ monkey.patch_all(thread=False)
else:
- monkey.patch_all(subprocess=True)
+ monkey.patch_all(subprocess=True, thread=False)
# monkey patch sendfile to make it none blocking
patch_sendfile()
Использование вышеуказанного патча со следующим wsgi больше не вызывает указанную ошибку:
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
from gevent import monkey
monkey.patch_all(thread=False)
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
from django.core.cache.backends.memcached import BaseMemcachedCache
BaseMemcachedCache.close = lambda self, **kwargs: None
Теперь я вижу другую и новую ошибку, но не знаю, связана ли она:
ProgrammingError: close cannot be used while an asynchronous query is underway
Это происходит, 1 из 10/15 запросов выполняет подсчет модели. Я подозреваю, что это ошибка моего приложения, которая теперь обнаружена.
@brockhaywood круто! кстати а какая у тебя версия gevent? Для вашей последней ошибки он умирает, действительно, похоже, не связан с пулеметом.
Ага, хорошие новости! В версии 1.0.1 gevent.
@tilgovi, поэтому мне интересно, не следует ли нам патчить Gunicorn, удаляя исправление thread monkey. Может быть, нам также следует установить wsgi.multithread
на False
? Мысли?
@benoitc Я могу воспроизвести новую ошибку, на которую я ссылался выше, с помощью очень простого приложения Django, которое имеет только одно представление и выполняет простой модельный запрос и подсчитывает, если я выполняю несколько одновременных запросов.
Есть ли у вас какие-либо предложения относительно того, какой компонент является наиболее вероятным виновником? Вероятно, это проблема gevent или психоэкран?
Скорее психогрин. Используете ли вы такой хук для его настройки?
def def_post_fork(server, worker):
from psycogreen.gevent import psyco_gevent
psyco_gevent.make_psycopg_green()
worker.log.info("Made Psycopg Green")
О, я на самом деле использую
def post_fork(server, worker):
from psycogreen.gevent import patch_psycopg
patch_psycopg()
Я попробую ваше предложение.
Ваш код будет более точным, если я прочитаю код psycogreen:
Хорошо, попробую открыть билет с помощью Psycogreen
можно попробовать использовать ловушку post_worker_init
вместо post_fork
?
Все еще возникает у меня при патче psycogreen в post_worker_init.
Я также отправил заявку на Psycogreen:
https://bitbucket.org/dvarrazzo/psycogreen/issue/2/databaseerror-used-with-asynchronous-query
@brockhaywood OK: / Также нашел эту ссылку: https://bitbucket.org/dvarrazzo/psycogreen-hg/issue/1/databaseerror-execute-used-with . Я не уверен, может ли это вам помочь.
Я посмотрел на это, и это похоже на ту же проблему, но, к сожалению, я не нашел решения.
@brockhaywood, не могли бы вы поделиться каким-нибудь простым примером кода, который помог бы мне воспроизвести проблему? Я посмотрю на это завтра.
Вот простой проект, который я использую для воспроизведения:
https://github.com/brockhaywood/gunicorn_gevent_issue
Благодарность!
Вск, 17 мая 2015 г., 22:34. Brockhaywood [email protected]
написал:
Вот простой проект, который я использую для воспроизведения:
https://github.com/brockhaywood/gunicorn_gevent_issue-
Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/benoitc/gunicorn/issues/927#issuecomment -102852497.
@benoitc есть мысли по этому
@brockhaywood, извини, у меня не было времени проверить это. Поскольку завтра меня посадят в рейс, я все равно буду :)
Спасибо
26 мая 2015 года в 13:17 «Бенуа Шено» [email protected] написал:
@brockhaywood https://github.com/brockhaywood извините, у меня не было времени
чтобы проверить это. Поскольку завтра меня посадят в рейс, я все равно буду :)-
Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/benoitc/gunicorn/issues/927#issuecomment -105652947.
Когда я увидел эту ветку, у меня возникла та же проблема с DatabaseWrapper.
Я могу подтвердить, что удаление параметра preload_app
из моего файла конфигурации Gunicorn решает проблему. Я использую:
(прыгает, так как мы наблюдаем те же проблемы, что описаны в этой ветке)
Похоже, эти проблемы вызваны исправлением проблемы № 478 (не пытайтесь исправлять мастер).
Поскольку не обезьяна исправляет мастер, предварительная загрузка приложения в корне создает несоответствие, если вы используете gevent worker. Любой код приложения, который запускается как часть предварительной загрузки, запускается в среде, не исправленной обезьяной. Любой код приложения, который выполняется в рабочем, выполняется в среде, пропатченной обезьяной.
Для нас, просто восстановив метод setup
для рабочего класса gevent
как он определен в 18.x, чтобы мастер был исправлен как обезьяна, и он был исправлен до предварительной загрузки приложения, исправлено все наши проблемы. Это включает ошибку DatabaseWrapper
, а также другую проблему, которую мы наблюдали, когда рабочие gevent зависали и превышали время ожидания. Никаких других изменений не потребовалось (например, нам не нужно отключать исправление обезьяны threads
).
Я все еще очень не решаюсь исправлять главный процесс как обезьяны, но если вы хотите это сделать, вы можете использовать серверные хуки вместо исправления самого Gunicorn. Если вы можете это сделать, я был бы рад, если мы сможем задокументировать это где-нибудь лучше, чем здесь.
Я думаю, что ближайший план для нас - создать (внутренний) форк Gunicorn с применением этого патча.
Я исследую перенос шага патча обезьяны в наш код wsgi, но это все еще кажется чем-то, что должно быть сделано внутри кода gunicorn (даже в качестве настраиваемой опции). Исправление в предварительно загруженном коде приложения так или иначе повлияет на мастер, и весь смысл будет заключаться в том, чтобы сохранить исправленное состояние рабочих процессов обезьяной в синхронизации с мастером. Применение патча master monkey в коде приложения означает, что разработчики приложений, которые зависят от этого поведения, всегда будут догонять любые изменения, которые Gunicorn вносит в то, когда и как обезьяна исправляет рабочего.
Если раннее исправление сработает, возможно, это следует рассматривать как изменение.
Я не могу вспомнить, было ли это когда-либо так и вызывали ли это проблемы, но с патчем обезьяны всегда сложно.
Наше собственное производственное приложение Gunicorn требует предварительной загрузки, а также требует исправления обезьяны в мастере (мы используем сценарий Pyramid / paste pserve
для запуска приложения и загрузки Gunicorn из файла ini; у нас есть оболочка вокруг него, чтобы быть уверен, что исправление обезьяны произойдет как можно скорее).
Я текущий сопровождающий gevent. Я буду рад рассмотреть любые проблемы в gevent, необходимые для улучшения работы этого сценария. Мы ожидаем, что скоро выпустим 1.1, и было бы здорово, если бы этот вариант поддерживался.
Я попытался применить ту же логику патча обезьяны в верхней части нашей реализации wsgi, и мы начали замечать проблему DatabaseWrapper
. Не совсем уверен, почему - если посмотреть на вызов wsgi в GeventWorker.setup
(как побочный эффект присваивания worker_class . Если я читаю код правильный.
Я буду следить, если у меня возникнет эврика или мне повезет с кодом приложения, но пока для нас исправление ранее в мастер-коде Gunicorn - единственное исправление, которое решает все наши проблемы.
@jamadden большое спасибо.
@jzupko обычно важно, чтобы исправление происходило до любого импорта, который может быть затронут. Вот почему я предложил сделать это с помощью сервера, например, поместив функцию post_fork
в файл gunicorn.conf.py
. Однако я только что понял, что предварительная загрузка приложения происходит до любого из перехватов сервера, и неясно, где это сделать.
@benoitc есть ли у нас какой-либо механизм для конфигурирования, специфичного для рабочего?
Я добавляю это к этапу выпуска 20 и предлагаю подумать о том, чтобы обезьяна внесла исправления в мастер, возможно, если это можно будет сделать без повторного введения таких проблем, как # 478.
@tilgovi у вас есть метод setup
рабочего, который, я думаю, можно использовать для этого.
Есть ли у кого-нибудь временное исправление, пока не выйдет 20.0? Или это единственный выход: отключить preload_app
или понизить до 18.0?
@fletom временное исправление для? Вы пробовали последний мастер? Это сработало для вас?
@benoitc Я имею в виду исправление ошибки "Объекты DatabaseWrapper".
Текущий мастер-пулемет вообще не работает для меня. На обычном 19.6.0 я получаю это (нормально):
[2017-01-05 15:46:32 -0500] [3222] [INFO] Starting gunicorn 19.6.0
[2017-01-05 15:46:32 -0500] [3222] [INFO] Listening at: http://127.0.0.1:8000 (3222)
[2017-01-05 15:46:32 -0500] [3222] [INFO] Using worker: gevent
[2017-01-05 15:46:32 -0500] [3226] [INFO] Booting worker with pid: 3226
[2017-01-05 15:46:32 -0500] [3227] [INFO] Booting worker with pid: 3227
[2017-01-05 15:46:32 -0500] [3228] [INFO] Booting worker with pid: 3228
[2017-01-05 15:46:32 -0500] [3229] [INFO] Booting worker with pid: 3229
И на последнем мастере со 100% точно такой же конфигурацией я получаю это, и, насколько я могу судить, ничего не прослушивает ни один порт:
[2017-01-05 15:47:19 -0500] [3308] [INFO] Starting gunicorn 19.6.0
[2017-01-05 15:47:19 -0500] [3308] [INFO] Listening at: (3308)
[2017-01-05 15:47:19 -0500] [3308] [INFO] Using worker: gevent
[2017-01-05 15:47:19 -0500] [3312] [INFO] Booting worker with pid: 3312
[2017-01-05 15:47:19 -0500] [3313] [INFO] Booting worker with pid: 3313
[2017-01-05 15:47:19 -0500] [3314] [INFO] Booting worker with pid: 3314
[2017-01-05 15:47:19 -0500] [3315] [INFO] Booting worker with pid: 3315
Кажется, прослушивается?
@fletom как запустить пулемет?
@benoitc В данном случае это gunicorn -c gunicorn_conf.py <appname>.wsgi
.
Мой gunicorn_conf.py
:
workers = 4
worker_class = 'gevent'
preload_app = False
Я натыкаюсь на эту проблему с gunicorn==18.0
. В gunicorn_conf.py у меня есть worker_class = 'gevent'
, preload_app = True
и пользовательские функции pre_fork
, on_starting
и on_reload
.
Размещение этих строк поверх файла gunicorn_conf.py, похоже, решает проблему для меня:
import gevent.monkey
gevent.monkey.patch_thread()
Обновлять:
У меня были эти строки в моем gunicorn.conf. Избавление от них решило проблему без исправления обезьяны.
import django
django.setup()
Из-за них django инициировал соединение до того, как Gunicorn произвел исправление обезьяны.
Предлагаемое @gukoff исправление не сработало для меня, я все еще получаю ту же ошибку 😞
Я собираюсь закрыть это и начать обсуждение с лейблом списка рассылки о вехе R20 для обезьяньего исправления арбитра в gevent. Если у вас возникли проблемы, связанные с чем-либо в этом обсуждении, и вы думаете, что это может быть ошибка в Gunicorn, пожалуйста, откройте проблему. Вы можете упомянуть его по номеру или ссылку на комментарии, если это поможет добавить контекст, но на данный момент это старый билет с параллельными разговорами о нескольких версиях Gunicorn и различных симптомах.
Самый полезный комментарий
Предлагаемое @gukoff исправление не сработало для меня, я все еще получаю ту же ошибку 😞