[英]Django not reconnecting when PostgreSQL dies, custom backend needed?
我一直在做一些測試,並且能夠確認將Django
與PostgreSQL
和PGBouncer
,它會在失去連接后不會自動重新連接。 老實說,我不確定這是錯誤還是設計使然。 如果是錯誤,我會很樂意報告,否則,除了其他自定義后端外,我想解釋一下為什么以及如何解決它。
通過在Django 1.8.4
和Django 1.8.6
上執行以下操作,我相當輕松地完成了這些測試:
>>>Model.objects.all().count()
24
# Restart postgres with `sudo service postgres restart`
>>>Model.objects.all().count()
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 318, in count
return self.query.get_count(using=self.db)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/query.py", line 466, in get_count
number = obj.get_aggregation(using, ['__count'])['__count']
File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/query.py", line 447, in get_aggregation
result = compiler.execute_sql(SINGLE)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 840, in execute_sql
cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/utils.py", line 98, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
OperationalError: server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
重啟PostgreSQL
運行查詢后我等待多長時間都沒關系,我仍然得到相同的結果。 我看到在Django
有代碼可以運行Select 1
來檢查連接,但這似乎不起作用。 回到Django 1.5.x
我們已經編寫了一個自定義的PostgreSQL后端來做同樣的事情,但是由於在升級時Django
似乎是內置的,所以將其刪除。 這是錯誤嗎?
編輯11/6/2015:在Django中,PostgreSQL后端實現了is_usable
函數,該函數對數據庫執行SELECT 1
。 但是,我無法找到任何用途is_usable
其他比close_if_unusable_or_obsolete
,但我找不到任何地方的任何用途。 我認為它將在一些捕獲異常並基於is_usable
重試/重新連接的數據庫包裝器中使用。
上面提到的代碼在Django 1.8中的django/db/backends/postgresql_psychopg2/base.py
中找到。
編輯2 2015年11月6日:好的,我為數據庫編寫了自己的自定義包裝程序,只是覆蓋了ensure_connection
方法來嘗試在連接斷開時嘗試重新連接到數據庫。 但是,在第一次嘗試訪問數據庫以進行會話時,我得到了另一個討厭的回溯。 但是,如果我立即再次查詢它就可以了。 如果我將我的工作包裝在try/except: pass
塊中,那么一切似乎都工作正常,但無法真正確定以后是否會引起問題。 這是回溯和代碼。
>>> c = Model.objects.all().count()
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 318, in count
return self.query.get_count(using=self.db)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/query.py", line 466, in get_count
number = obj.get_aggregation(using, ['__count'])['__count']
File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/query.py", line 447, in get_aggregation
result = compiler.execute_sql(SINGLE)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 838, in execute_sql
cursor = self.connection.cursor()
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/base/base.py", line 164, in cursor
cursor = self.make_cursor(self._cursor())
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/base/base.py", line 135, in _cursor
self.ensure_connection()
File "/usr/lib/python2.7/dist-packages/custom/db/backends/postgresql_psycopg2/base.py", line 73, in ensure_connection
self._reconnect()
File "/usr/lib/python2.7/dist-packages/custom/db/backends/postgresql_psycopg2/base.py", line 63, in _reconnect
self.connect()
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/base/base.py", line 120, in connect
self.set_autocommit(self.settings_dict['AUTOCOMMIT'])
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/base/base.py", line 295, in set_autocommit
self._set_autocommit(autocommit)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/postgresql_psycopg2/base.py", line 218, in _set_autocommit
self.connection.autocommit = autocommit
File "/usr/local/lib/python2.7/dist-packages/django/db/utils.py", line 97, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/postgresql_psycopg2/base.py", line 218, in _set_autocommit
self.connection.autocommit = autocommit
ProgrammingError: autocommit cannot be used inside a transaction
現在查看代碼:
from django.db.backends.postgresql_psycopg2.base import DatabaseError, \
IntegrityError, DatabaseWrapper as PostgresWrapper
class DatabaseWrapper(PostgresWrapper):
def _reconnect(self):
try:
self.connect()
except (DatabaseError, OperationalError):
pass
def ensure_connection(self):
"""
Guarantees that a connection to the database is established.
"""
if self.connection is None:
with self.wrap_database_errors:
self._reconnect()
else:
try:
self.connection.cursor().execute('SELECT 1')
except (DatabaseError, OperationalError):
self._reconnect()
我想我終於明白了。 不能完全確定我的第一種方法有什么問題,但是這種方法似乎工作得更好。
class DatabaseWrapper(PostgresWrapper):
def _cursor(self):
if self.connection is not None:
if not self.is_usable():
self.connection.close()
self.connection = None
return super(DatabaseWrapper, self)._cursor()
編輯:結束對此的開源。 我不確定是否100%需要它,但是在服務器上重新啟動Postgres服務后,它是否可以正常工作。 您可以在pypi上以django-postgreconnect
找到它,在GitHub上: https : //github.com/mackeyja92/django-postgreconnect 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.