Обновление 3/4:
Я провел некоторое тестирование и доказал, что использование обработчика событий checkout для проверки отключений работает с Elixir. Начиная думать, что моя проблема как-то связана с вызовом session.commit()
из подпроцесса? Обновление: я просто опроверг себя, вызвав session.commit()
в подпроцессе, обновленный пример ниже. Я использую многопроцессорный модуль для создания подпроцесса.
Вот код, который показывает, как он должен работать (даже без использования pool_recycle
!):
from sqlalchemy import exc
from sqlalchemy import event
from sqlalchemy.pool import Pool
from elixir import *
import multiprocessing as mp
class SubProcess(mp.Process):
def run(self):
a3 = TestModel(name="monkey")
session.commit()
class TestModel(Entity):
name = Field(String(255))
@event.listens_for(Pool, "checkout")
def ping_connection(dbapi_connection, connection_record, connection_proxy):
cursor = dbapi_connection.cursor()
try:
cursor.execute("SELECT 1")
except:
# optional - dispose the whole pool
# instead of invalidating one at a time
# connection_proxy._pool.dispose()
# raise DisconnectionError - pool will try
# connecting again up to three times before raising.
raise exc.DisconnectionError()
cursor.close()
from sqlalchemy import create_engine
metadata.bind = create_engine("mysql://foo:bar@localhost/some_db", echo_pool=True)
setup_all(True)
subP = SubProcess()
a1 = TestModel(name='foo')
session.commit()
# pool size is now three.
print "Restart the server"
raw_input()
subP.start()
#a2 = TestModel(name='bar')
#session.commit()
Обновление 2:
Я вынужден найти другое решение, так как после версии 1.2.2 MySQL-python прекращает поддержку параметраconnect. У кого-нибудь есть решение? : \
Обновление 1 (старое решение, не работает для версий MySQL-python> 1.2.2):
Нашел решение: передача connect_args={'reconnect':True}
на вызов create_engine
решает проблему, автоматически восстанавливает соединение. Кажется, даже не нужен обработчик событий checkout.
Итак, в примере из вопроса:
metadata.bind = create_engine("mysql://foo:bar@localhost/db_name", pool_size=100, pool_recycle=3600, connect_args={'reconnect':True})
Оригинальный вопрос:
Совершенно немного погуглил для этой проблемы и, похоже, не нашел решения, специфичного для Elixir - я пытаюсь использовать пример " Disconnect Handling - Pessimistic " из документации по SQLAlchemy для обрабатывать MySQL отключается. Однако, когда я проверяю это (перезагружая сервер MySQL), перед обработчиком события checkout возникает ошибка «Сервер MySQL ушел».
Вот код, который я использую для инициализации эликсира:
##### Initialize elixir/SQLAlchemy
# Disconnect handling
from sqlalchemy import exc
from sqlalchemy import event
from sqlalchemy.pool import Pool
@event.listens_for(Pool, "checkout")
def ping_connection(dbapi_connection, connection_record, connection_proxy):
logging.debug("***********ping_connection**************")
cursor = dbapi_connection.cursor()
try:
cursor.execute("SELECT 1")
except:
logging.debug("######## DISCONNECTION ERROR #########")
# optional - dispose the whole pool
# instead of invalidating one at a time
# connection_proxy._pool.dispose()
# raise DisconnectionError - pool will try
# connecting again up to three times before raising.
raise exc.DisconnectionError()
cursor.close()
metadata.bind= create_engine("mysql://foo:bar@localhost/db_name", pool_size=100, pool_recycle=3600)
setup_all()
Я создаю объекты сущностей эликсира и сохраняю их с помощью session.commit()
, во время которого я вижу сообщение "ping_connection", сгенерированное из события, определенного выше. Тем не менее, когда я перезагружаю сервер mysql и снова тестирую его, происходит сбой, когда сервер mysql исчезает перед событием ping-соединения.
Вот трассировка стека, начиная с соответствующих строк:
File "/usr/local/lib/python2.6/dist-packages/elixir/entity.py", line 1135, in get_by
return cls.query.filter_by(*args, **kwargs).first()
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/query.py", line 1963, in first
ret = list(self[0:1])
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/query.py", line 1857, in __getitem__
return list(res)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/query.py", line 2032, in __iter__
return self._execute_and_instances(context)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/query.py", line 2047, in _execute_and_instances
result = conn.execute(querycontext.statement, self._params)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/engine/base.py", line 1399, in execute
params)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/engine/base.py", line 1532, in _execute_clauseelement
compiled_sql, distilled_params
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/engine/base.py", line 1640, in _execute_context
context)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/engine/base.py", line 1633, in _execute_context
context)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/engine/default.py", line 330, in do_execute
cursor.execute(statement, parameters)
File "/usr/lib/pymodules/python2.6/MySQLdb/cursors.py", line 166, in execute
self.errorhandler(self, exc, value)
File "/usr/lib/pymodules/python2.6/MySQLdb/connections.py", line 35, in defaulterrorhandler
raise errorclass, errorvalue
OperationalError: (OperationalError) (2006, 'MySQL server has gone away')