2015-11-06 106 views
1

我一直在做一些測試,並已能夠確認使用DjangoPostgreSQLPGBouncer它不會自動重新連接失去它的連接。說實話,我不確定這是否是一個錯誤,或者如果這是設計。如果它是一個錯誤,我會高興地報告它,如果不是,我想解釋爲什麼以及如何繞過它而不是另一個自定義後端。當PostgreSQL死亡時,Django不會重新連接,需要自定義後端?

我很容易做這些測試通過執行以下操作上Django 1.8.4Django 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。這是一個錯誤?

編輯2015年11月6日:在Django中,PostgreSQL後端實現is_usable功能的數據庫上做了SELECT 1。但是,除close_if_unusable_or_obsolete之外,我找不到is_usable的任何用法,但我找不到任何地方的任何用法。我認爲它會在某些數據庫封裝器中使用,該封裝器基於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() 

回答

1

我想我想通了......最後。不完全確定我的第一種方法出了什麼問題,但這個問題似乎正在好得多。

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

相關問題