2014-02-18 3 views
7

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

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

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

отслеживающий глубоко в 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') 

Возможные попытки файлик:

  • В this question, один из комментариев рекомендуем pinging серверу MySQL время от времени, чтобы сохранить его (соединение?) вживую. Я не уверен, как это сделать через ORM. (должен я просто SELECT 1 каждый час, скажем?)
  • В this github peewee issue, который был открыт 4 месяца назад, указана одна и та же ошибка, хотя там утверждается, что он решен (и я использую более новую версию).
  • В 7 year old issue из trac, одно из предложений заключается в увеличении таймаута MySQL на 3 дня.
  • В этом forum discussion предлагается вариант увеличения времени ожидания MySQL, но предлагается альтернатива «использования опции autoReconnect для соединителя JDBC MySQL». Я попытался выяснить, существует ли такая опция для модуля MySQLdb Python, но не удалось найти.
  • Я нашел это MySQL reference page о поведении повторного подключения, но это немного сложно для моего понимания MySQL (обычно я работаю только с ОРМ), и я не знаю, как его применить от peewee.

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

+0

Проверьте значение 'wait_timeout' в MySQL –

+0

Я предполагаю, что это 8 часов; разве это не по умолчанию? – Bach

+0

Да, это по умолчанию. –

ответ

5

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

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

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

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

+1

Это действительно похоже на то, что нужно делать. Однако этого было непросто; не было ни одного метода, который мог бы найти, что я мог бы обернуть такой структурой «try ... except», каждый раз, когда ошибка была поднята из другого места. Вот что приятно - и проблематично - об ORM; они становятся почти прозрачными в вашем коде. Во всяком случае, я закончил пинговать сервер, и, надеюсь, люди «peewee» будут реализовывать внутренний дополнительный метод повторного подключения в один прекрасный день. – Bach

+0

В таких крайних случаях вы можете поместить try/except вокруг метода main() вашего скрипта. – geertjanvdk

+0

Нет, я никогда этого не сделаю ... Это не сценарий, это огромное многопоточное программное обеспечение ... Я просто утверждаю, что это ответственность ОРМ, иначе я должен «вторгнуться» на его территорию, излишний. – Bach

0

Я разрешил эту проблему.

Мое решение использует пул соединений mysql PooledMySQLDatabase от playhouse.pool.

пожалуйста, прочитайте: https://github.com/coleifer/peewee/issues/239

from peewee import * 
from playhouse.pool import * 
+0

Просто примечание: этот модуль считается экспериментальным, и его может быть опасно применять для производства. – Bach

7

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

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

где для функции пинг там is:

Проверяет, связано ли соединение с сервером w orking. Если он опустился до , произойдет автоматическое повторное соединение.

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

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

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

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

+0

Pinging перед запуском запроса считается анти-шаблоном, который тратит ресурсы и является ненадежным: https://www.percona.com/blog/2010/05/05/checking-for-a-live-database-connection-considered -harmful / –

Смежные вопросы