Повторное подключение MySQL по таймауту

у меня есть программа Python, которая работает на фоне в течение нескольких недель, и делает запросы к базе данных время от времени. Для этого я использую ORM peewee (версия 2.2.1). Я использую MySQL в качестве бэкэнда.

в последнее время я столкнулся с повторяющейся проблемой с доступом к БД, обычно после нескольких дней запуска программы. Ошибка, вызванная peewee и

peewee.OperationalError: (2006, 'MySQL server has gone away')

traceback глубоко в peewee. Я размещаю его здесь, но как мой virtualenv делает имена файлов слишком длинными, я сокращаю их:

  File ".../local/lib/python2.7/site-packages/peewee.py", line 2910, in save
    ret_pk = self.insert(**field_dict).execute()
  File ".../local/lib/python2.7/site-packages/peewee.py", line 2068, in execute
    return self.database.last_insert_id(self._execute(), self.model_class)
  File ".../local/lib/python2.7/site-packages/peewee.py", line 1698, in _execute
    return self.database.execute_sql(sql, params, self.require_commit)
  File ".../local/lib/python2.7/site-packages/peewee.py", line 2232, in execute_sql
    self.commit()
  File ".../local/lib/python2.7/site-packages/peewee.py", line 2104, in __exit__
    reraise(new_type, new_type(*exc_value.args), traceback)
  File ".../local/lib/python2.7/site-packages/peewee.py", line 2223, in execute_sql
    res = cursor.execute(sql, params or ())
  File ".../local/lib/python2.7/site-packages/MySQLdb/cursors.py", line 205, in execute
    self.errorhandler(self, exc, value)
  File ".../local/lib/python2.7/site-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
peewee.OperationalError: (2006, 'MySQL server has gone away')

возможные попытки решения, которые я нашел:

  • на этот вопрос, один из комментариев предлагает пинговать MySQL сервер время от времени, чтобы сохранить его (соединение?) живой. Однако я не уверен, как это сделать через ORM. (должен ли я просто SELECT 1 каждый час, скажем?)
  • на этот выпуск GitHub peewee, который был открыт 4 месяца назад та же ошибка упоминается, хотя там утверждается, что она решена (и я использую более новую версию).
  • на 7-летний выпуск of trac, одно предложение-увеличить тайм-аут MySQL в течение 3 дней.
  • в этой форум параметр увеличения MySQLпредлагается тайм-аут, но предлагается альтернатива "использование опции autoReconnect для MySQL JDBC connector". Я попытался выяснить, если такой опция существует для Python MySQLdb модуль, но не смог найти.
  • и справочная страница MySQL о поведении повторного подключения, но это немного сложно для моего понимания MySQL (обычно я работаю только с ORMs), и я не знаю, как применить любой из них из peewee.

даже если я могу пинговать базу данных, чтобы сохранить соединение живым в течение более длительных периодов, я думаю, что это считается плохой практикой, чтобы сохранить соединение живым когда в этом нет необходимости. Есть ли способ снова открыть соединение через ORM? Я рассматриваю как pinging, так и увеличение тайм-аута MySQL как обходные пути, в то время как реальным решением было бы снова подключиться, когда это необходимо (и реальное решение-это то, что я прошу).

3 ответов


вы должны поймать исключение и на основании которых ошибки, восстановить или сделать что-то еще. Является ли это тайм-аут соединения, или сетевая проблема, или MySQL должен быть перезапущен.

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

while True:
    try:
        # do your database stuff
    except peewee.OperationalError as exc:
        # Oops! We have to try to reconnect

на самом деле не имеет значения, используете ли вы ORM или нет. Однако ORM может предложить это функциональность.


у меня была та же проблема, и для peewee с помощью MySQLdb я получил следующее решение при инициализации экземпляра базы данных MySQL:

db = MySQLDatabase(db_name, user=db_username, passwd=db_password, host=db_host, port=db_port)
db.get_conn().ping(True)

где для функции ping есть:

проверяет, работает ли соединение с сервером. Если это пошел вниз, предпринята попытка автоматического повторного подключения.

эта функция может использоваться клиентами, которые остаются без дела в течение длительного времени while, чтобы проверить, закрыт ли сервер соединение и при необходимости подключитесь заново.

New в 1.2.2: принимает необязательный параметр повторного подключения. Если это правда, то клиент попытается восстановить соединение. Обратите внимание, что этот параметр настойчивый. По умолчанию, это в MySQL

нестандартные. Вы должны предположить, что ping () выполняет неявное откат; используется только при запуске новой транзакции. Вы были предупрежденный.

на db.get_conn().ping.__doc__. Виду, что db.get_conn().ping(True) должен использоваться, если вы снова создадите другое соединение. Поэтому, если вы снова подключитесь (через db.connect() например), вы должны повторить пинг.


я решил эту проблему.

мое решение - использовать MySQL connection pool PooledMySQLDatabase С playhouse.pool модуль.

читайте: https://github.com/coleifer/peewee/issues/239

from peewee import *
from playhouse.pool import *