簡體   English   中英

PostgreSQL死后,Django無法重新連接,需要自定義后端嗎?

[英]Django not reconnecting when PostgreSQL dies, custom backend needed?

我一直在做一些測試,並且能夠確認將DjangoPostgreSQLPGBouncer ,它會在失去連接后不會自動重新連接。 老實說,我不確定這是錯誤還是設計使然。 如果是錯誤,我會很樂意報告,否則,除了其他自定義后端外,我想解釋一下為什么以及如何解決它。

通過在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似乎是內置的,所以將其刪除。 這是錯誤嗎?

編輯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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM