Вопрос

Я запускаю приложение Django.Раньше было под Apache + mod_python, и все было ок.Перешел на Lighttpd + FastCGI.Теперь я случайно получаю следующее исключение (ни место, ни время его появления не кажутся предсказуемыми).Поскольку оно случайное и появляется только после переключения на FastCGI, я предполагаю, что это как-то связано с какими-то настройками.

При поиске в Google нашел несколько результатов, но они, похоже, связаны с установкой maxrequests=1.Однако я использую значение по умолчанию, равное 0.

Есть идеи, где искать?

ПС.Я использую PostgreSQL.Возможно, это тоже связано с этим, поскольку исключение возникает при выполнении запроса к базе данных.

 File "/usr/lib/python2.6/site-packages/django/core/handlers/base.py", line 86, in get_response
   response = callback(request, *callback_args, **callback_kwargs)

 File "/usr/lib/python2.6/site-packages/django/contrib/admin/sites.py", line 140, in root
   if not self.has_permission(request):

 File "/usr/lib/python2.6/site-packages/django/contrib/admin/sites.py", line 99, in has_permission
   return request.user.is_authenticated() and request.user.is_staff

 File "/usr/lib/python2.6/site-packages/django/contrib/auth/middleware.py", line 5, in __get__
   request._cached_user = get_user(request)

 File "/usr/lib/python2.6/site-packages/django/contrib/auth/__init__.py", line 83, in get_user
   user_id = request.session[SESSION_KEY]

 File "/usr/lib/python2.6/site-packages/django/contrib/sessions/backends/base.py", line 46, in __getitem__
   return self._session[key]

 File "/usr/lib/python2.6/site-packages/django/contrib/sessions/backends/base.py", line 172, in _get_session
   self._session_cache = self.load()

 File "/usr/lib/python2.6/site-packages/django/contrib/sessions/backends/db.py", line 16, in load
   expire_date__gt=datetime.datetime.now()

 File "/usr/lib/python2.6/site-packages/django/db/models/manager.py", line 93, in get
   return self.get_query_set().get(*args, **kwargs)

 File "/usr/lib/python2.6/site-packages/django/db/models/query.py", line 304, in get
   num = len(clone)

 File "/usr/lib/python2.6/site-packages/django/db/models/query.py", line 160, in __len__
   self._result_cache = list(self.iterator())

 File "/usr/lib/python2.6/site-packages/django/db/models/query.py", line 275, in iterator
   for row in self.query.results_iter():

 File "/usr/lib/python2.6/site-packages/django/db/models/sql/query.py", line 206, in results_iter
   for rows in self.execute_sql(MULTI):

 File "/usr/lib/python2.6/site-packages/django/db/models/sql/query.py", line 1734, in execute_sql
   cursor.execute(sql, params)

OperationalError: server closed the connection unexpectedly
       This probably means the server terminated abnormally
       before or while processing the request.
Это было полезно?

Решение 5

В конце концов я снова переключился на Apache + mod_python (кроме этой, у меня были и другие случайные ошибки с fcgi), и теперь все хорошо и стабильно.

Вопрос до сих пор остается открытым.Если у кого-то возникнет эта проблема в будущем и он ее решит, он может записать решение здесь для дальнейшего использования.:)

Другие советы

Возможное решение: http://groups.google.com/group/django-users/browse_thread/thread/2c7421cdb9b99e48

До недавнего времени мне было любопытно проверить это на Django 1.1.1.Будет ли это исключение будет брошено снова...сюрприз, там это снова было.Это заняло у меня немного время, чтобы отладить это, полезный намек был что он показывает только при (пред)форкинге.Так что для тех, кто получает случайно Эти исключения, я могу сказать...исправить Ваш код:) Ok..Серьезно, там всегда несколько способов сделать это, так позвольте мне Firs объяснить, где это Meme it проблема во-первых.Если вы получаете доступ к базе данных когда любой из ваших модулей будет импортирован как, напримерчтение конфигурации из базы данных, то вы получите эту ошибку.Когда ваше приложение fastcgi-prefork запускает, сначала импортирует все модули, и только после этого разводит детей.Если вы установили db соединение во время импорта все дети процессы будет иметь точную копию этого Meme it объект.Это соединение осуществляется закрывается в конце этапа запроса (сигнал request_finished).Итак, сначала ребенок, который будет вызван для обработки ваш запрос, закроет это подключение.Но что будет с остальные дочерние процессы?Они поверит, что у них есть открытые и предположительно работает подключение к db, поэтому любая операция db вызовет исключение.Почему это не отображается нитевидная модель исполнения?Полагаю, потому что потоки используют один и тот же объект и знать, когда любой другой поток замыкающее соединение.Как это исправить?Лучший способ - исправить свой код...но Иногда это может быть трудно.Другой вариант, на мой взгляд, вполне чистый, должен писать где-то в вашем Meme it приложение небольшой кусок кода:

from django.db import connection 
from django.core import signals 
def close_connection(**kwargs): 
    connection.close() 
signals.request_started.connect(close_connection) 

Не идеальная мысль, двойное подключение к БД — в лучшем случае обходной путь.


Возможное решение:используя пул соединений (pgpool, pgbouncer), чтобы соединения с БД были объединены в пул, стабильны и быстро передавались вашим демонам FCGI.

Проблема в том, что это вызывает еще одну ошибку: psycopg2 вызывает Ошибка интерфейса потому что он дважды пытается отключиться (pgbouncer уже справился с этим).

Теперь виновником является сигнал Джанго. запрос_закончен запуск соединение.закрыть(), и громко глючит, даже если он уже отключен.Я не думаю, что такое поведение желательно, поскольку если запрос уже завершен, нас больше не волнует соединение с БД.Патч для исправления этого должен быть простым.

Соответствующая обратная связь:

 /usr/local/lib/python2.6/dist-packages/Django-1.1.1-py2.6.egg/django/core/handlers/wsgi.py in __call__(self=<django.core.handlers.wsgi.WSGIHandler object at 0x24fb210>, environ={'AUTH_TYPE': 'Basic', 'DOCUMENT_ROOT': '/storage/test', 'GATEWAY_INTERFACE': 'CGI/1.1', 'HTTPS': 'off', 'HTTP_ACCEPT': 'application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate', 'HTTP_AUTHORIZATION': 'Basic dGVzdGU6c3VjZXNzbw==', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_COOKIE': '__utma=175602209.1371964931.1269354495.126938948...none); sessionid=a1990f0d8d32c78a285489586c510e8c', 'HTTP_HOST': 'www.rede-colibri.com', ...}, start_response=<function start_response at 0x24f87d0>)
  246                 response = self.apply_response_fixes(request, response)
  247         finally:
  248             signals.request_finished.send(sender=self.__class__)
  249 
  250         try:
global signals = <module 'django.core.signals' from '/usr/local/l.../Django-1.1.1-py2.6.egg/django/core/signals.pyc'>, signals.request_finished = <django.dispatch.dispatcher.Signal object at 0x1975710>, signals.request_finished.send = <bound method Signal.send of <django.dispatch.dispatcher.Signal object at 0x1975710>>, sender undefined, self = <django.core.handlers.wsgi.WSGIHandler object at 0x24fb210>, self.__class__ = <class 'django.core.handlers.wsgi.WSGIHandler'>
 /usr/local/lib/python2.6/dist-packages/Django-1.1.1-py2.6.egg/django/dispatch/dispatcher.py in send(self=<django.dispatch.dispatcher.Signal object at 0x1975710>, sender=<class 'django.core.handlers.wsgi.WSGIHandler'>, **named={})
  164 
  165         for receiver in self._live_receivers(_make_id(sender)):
  166             response = receiver(signal=self, sender=sender, **named)
  167             responses.append((receiver, response))
  168         return responses
response undefined, receiver = <function close_connection at 0x197b050>, signal undefined, self = <django.dispatch.dispatcher.Signal object at 0x1975710>, sender = <class 'django.core.handlers.wsgi.WSGIHandler'>, named = {}
 /usr/local/lib/python2.6/dist-packages/Django-1.1.1-py2.6.egg/django/db/__init__.py in close_connection(**kwargs={'sender': <class 'django.core.handlers.wsgi.WSGIHandler'>, 'signal': <django.dispatch.dispatcher.Signal object at 0x1975710>})
   63 # when a Django request is finished.
   64 def close_connection(**kwargs):
   65     connection.close()
   66 signals.request_finished.connect(close_connection)
   67 
global connection = <django.db.backends.postgresql_psycopg2.base.DatabaseWrapper object at 0x17b14c8>, connection.close = <bound method DatabaseWrapper.close of <django.d...ycopg2.base.DatabaseWrapper object at 0x17b14c8>>
 /usr/local/lib/python2.6/dist-packages/Django-1.1.1-py2.6.egg/django/db/backends/__init__.py in close(self=<django.db.backends.postgresql_psycopg2.base.DatabaseWrapper object at 0x17b14c8>)
   74     def close(self):
   75         if self.connection is not None:
   76             self.connection.close()
   77             self.connection = None
   78 
self = <django.db.backends.postgresql_psycopg2.base.DatabaseWrapper object at 0x17b14c8>, self.connection = <connection object at 0x1f80870; dsn: 'dbname=co...st=127.0.0.1 port=6432 user=postgres', closed: 2>, self.connection.close = <built-in method close of psycopg2._psycopg.connection object at 0x1f80870>

Обработка исключений здесь может добавить больше снисходительности:

/usr/local/lib/python2.6/dist-packages/Django-1.1.1-py2.6.egg/django/db/__init__.py

   63 # when a Django request is finished.
   64 def close_connection(**kwargs):
   65     connection.close()
   66 signals.request_finished.connect(close_connection)

Или это можно было бы лучше обработать в psycopg2, чтобы не выдавать фатальные ошибки, если все, что мы пытаемся сделать, это отключиться, а это уже так:

/usr/local/lib/python2.6/dist-packages/Django-1.1.1-py2.6.egg/django/db/backends/__init__.py

   74     def close(self):
   75         if self.connection is not None:
   76             self.connection.close()
   77             self.connection = None

В остальном у меня мало идей.

При переключении вы меняли версии клиента/сервера PostgreSQL?

Я видел подобные проблемы с php+mysql, и виновником была несовместимость версий клиент/сервер (хотя у них была одна и та же основная версия!)

Похоже на возможные проблемы с резьбой.Джанго это нет гарантированная потокобезопасность, хотя в документации, похоже, указано, что Django/FCGI можно запускать таким образом.Попробуйте запустить prefork, а затем выбить все дерьмо из сервера.Если проблема исчезнет...

Возможно, переменная среды PYTHONPATH и PATH различна для обеих настроек (Apache + mod_python и Lighttpd + FastCGI).

Я исправил аналогичную проблему при использовании модели geodjango, которая не использовала ORM по умолчанию для одной из своих функций.Когда я добавил строку для закрытия соединения вручную, ошибка исчезла.

http://code.djangoproject.com/ticket/9437

Однако я все еще вижу случайную ошибку (~ 50% запросов) при выполнении действий с входом/сессиями пользователя.

Недавно я столкнулся с той же проблемой (lighttpd, fastcgi и postgre).Безуспешно искал решение несколько дней и в крайнем случае перешел на MySQL.Проблема ушла.

Почему бы не хранить сеанс в кеше?Набор

SESSION_ENGINE = "django.contrib.sessions.backends.cache"

Также вы можете попробовать использовать postgres с pgbouncer (postgres — сервер prefork и не любит много подключений/отключений за раз), но сначала проверьте свой postgresql.log.

Другая версия - у вас много записей в сессионных таблицах и очистка django-admin.py может помочь.

Проблема может быть в основном с импортом.По крайней мере, это то, что случилось со мной.Я написал собственное решение, ничего не найдя в Интернете.Пожалуйста, проверьте мой блог здесь: Простая утилита Python для проверки всех импортов в вашем проекте

Конечно, это поможет вам довольно быстро найти решение исходной проблемы, а не фактическое решение вашей проблемы само по себе.

Переход с метода = prefork на метод = резьба решил для меня проблему.

Я пытаюсь дать ответ на этот вопрос, даже если в качестве основы использую не Джанго, а пирамиду.Я столкнулся с этой проблемой уже давно.Проблема заключалась в том, что было очень сложно выдать эту ошибку для тестов...В любом случае.Наконец, я решил эту проблему, проанализировав все сеансы, сеансы с ограниченной областью действия, экземпляры сеансов, механизмы, соединения и т. д.Я нашел это:

http://docs.sqlalchemy.org/en/rel_0_7/core/pooling.html#disconnect-handling-pessimistic

Этот подход просто добавляет прослушиватель в пул соединений механизма.В прослушивателе к базе данных запрашивается статический выбор.В случае сбоя пул попытается установить новое соединение с базой данных до того, как произойдет сбой вообще.Важный:Это происходит до того, как в базу данных будет отправлено что-либо еще.Таким образом, можно предварительно проверить соединение, что предотвращает сбой остальной части вашего кода.

Это не чистое решение, поскольку оно не устраняет саму ошибку, но работает как шарм.Надеюсь, это кому-то поможет.

Применимая цитата:

"2019 anyone?" - half of YouTube comments, circa 2019

Если кто-то все еще сталкивается с этим, убедитесь, что ваше приложение «с готовностью разветвляется», так что ваш драйвер БД Python (psycopg2 для меня) не распределяет ресурсы между процессами.

Я решил эту проблему в uWSGI, добавив lazy-apps = true вариант, который приводит к тому, что процессы приложения сразу же разветвляются, а не ждут копирования при записи.Я предполагаю, что другие хосты WSGI/FastCGI имеют аналогичные возможности.

Рассматривали ли вы возможность перехода на Python 2.5.x (в частности, 2.5.4)?Я не думаю, что Django можно считать зрелым на Python 2.6, поскольку в нем есть некоторые обратно несовместимые изменения.Однако я сомневаюсь, что это решит вашу проблему.

Кроме того, в Django 1.0.2 исправлены некоторые мелкие гнусные ошибки, поэтому убедитесь, что вы их используете.Это вполне может решить вашу проблему.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top