gpt4 book ai didi

python - Django + FastCGI - 随机引发 OperationalError

转载 作者:太空狗 更新时间:2023-10-29 21:09:12 25 4
gpt4 key购买 nike

我正在运行 Django 应用程序。之前在Apache + mod_python下有过,都OK。切换到 Lighttpd + FastCGI。现在我随机得到以下异常(它出现的地点和时间似乎都无法预测)。由于它是随机的,并且仅在切换到 FastCGI 后出现,我认为它与某些设置有关。

搜索时发现了一些结果,但它们似乎与设置 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.

最佳答案

可能的解决方案:http://groups.google.com/group/django-users/browse_thread/thread/2c7421cdb9b99e48

Until recently I was curious to test this on Django 1.1.1. Will this exception be thrown again... surprise, there it was again. It took me some time to debug this, helpful hint was that it only shows when (pre)forking. So for those who getting randomly those exceptions, I can say... fix your code :) Ok.. seriously, there are always few ways of doing this, so let me firs explain where is a problem first. If you access database when any of your modules will import as, e.g. reading configuration from database then you will get this error. When your fastcgi-prefork application starts, first it imports all modules, and only after this forks children. If you have established db connection during import all children processes will have an exact copy of that object. This connection is being closed at the end of request phase (request_finished signal). So first child which will be called to process your request, will close this connection. But what will happen to the rest of the child processes? They will believe that they have open and presumably working connection to the db, so any db operation will cause an exception. Why this is not showing in threaded execution model? I suppose because threads are using same object and know when any other thread is closing connection. How to fix this? Best way is to fix your code... but this can be difficult sometimes. Other option, in my opinion quite clean, is to write somewhere in your application small piece of code:

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 引发了一个InterfaceError,因为它试图断开连接两次(pgbouncer 已经处理了这个)。

现在的罪魁祸首是 Django 信号 request_finished 触发 connection.close(),即使它已经断开连接也会大声失败。我不认为需要这种行为,就好像请求已经完成一样,我们不再关心数据库连接了。纠正这个问题的补丁应该很简单。

相关回溯:

 /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

除此之外,我缺乏想法。

关于python - Django + FastCGI - 随机引发 OperationalError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/393637/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com