Manejar el reinicio mysql en SQLAlchemy
error-handling pylons (2)
Puede usar el proxy SQLAlchemy para el manejo de excepciones en cada consulta SQL:
from sqlalchemy.interfaces import ConnectionProxy
class MyProxy(ConnectionProxy):
def cursor_execute(self, execute, cursor, statement, parameters, context, executemany):
try:
return execute(cursor, statement, parameters, context)
except sqlalchemy.exc.OperationalError:
# Handle this exception
pass
Para conectar este proxy, debes hacerlo en config / enviroment.py
engine = engine_from_config(config, ''sqlalchemy.'', proxy=MyProxy())
O escriba middleware para el manejo de excepciones en cada consulta http:
class MyMiddleware(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
try:
return self.app(environ, start_response)
except sqlalchemy.exc.OperationalError:
start_response(
''500 Internal Server Error'',
[(''content-type'', ''text/html'')])
return [''error page/n'']
Para conectar este middleware en orden de pila según lo necesite o simplemente en config / middleware.py:
# CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
app = MyMiddleware(app)
La aplicación My Pylons utiliza un servidor MySQL local a través de SQLAlchemy y python-MySQLdb. Cuando se reinicia el servidor, las conexiones abiertas abiertas aparentemente están cerradas, pero la aplicación no sabe nada de esto y, aparentemente, cuando trata de usar dicha conexión, recibe el mensaje "El servidor MySQL se ha ido":
File ''/usr/lib/pymodules/python2.6/sqlalchemy/engine/default.py'', line 277 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'')
Esta excepción no se detecta en ninguna parte, por lo que se extiende al usuario. Si debo manejar esta excepción en algún lugar de mi código, muestre el lugar para dicho código en una aplicación Pylons WSGI. ¿O tal vez hay una solución en SA en sí?
Vea EDITAR en la parte inferior para la solución probada
No lo intenté, pero tal vez usar PoolListener es un camino por recorrer.
Podrías hacer algo como esto:
class MyListener(sqlalchemy.interfaces.PoolListener):
def __init__(self):
self.retried = False
def checkout(self, dbapi_con, con_record, con_proxy):
try:
dbapi_con.info() # is there any better way to simply check if connection to mysql is alive?
except sqlalchemy.exc.OperationalError:
if self.retried:
self.retried = False
raise # we do nothing
self.retried = True
raise sqlalchemy.exc.DisconnectionError
# next, code according to documentation linked above follows
e = create_engine("url://", listeners=[MyListener()])
De esta forma, cada vez que se va a verificar la conexión desde el grupo que probamos, si está realmente conectada al servidor. Si no, le damos a sqlalchemy una oportunidad de volver a conectar. Después de eso, si el problema sigue ahí, lo dejamos ir.
PD: No probé si esto funciona.
Editar: En cuanto a las Torres, las modificaciones a la inicialización del motor que se muestran arriba deberían hacerse en la función your_app.model.init_model (Pylons 0.9.7) o your_app.config.environment.load_environment (Pylons 1.0) : estas son las lugares lugar donde se crea la instancia del motor.
EDITAR
De acuerdo. Pude reproducir la situación descrita. El código anterior necesita algunos cambios para poder funcionar. A continuación se muestra cómo se debe hacer. Además, no importa si es 0.9.7 o 1.0.
Debe editar su_app / config / environment.py. Coloque estas exportaciones en la parte superior del archivo:
import sqlalchemy
import sqlalchemy.interfaces
import _mysql_exceptions
Y el final de la función load_environment debería verse así:
class MyListener(sqlalchemy.interfaces.PoolListener):
def __init__(self):
self.retried = False
def checkout(self, dbapi_con, con_record, con_proxy):
try:
dbapi_con.cursor().execute(''select now()'')
except _mysql_exceptions.OperationalError:
if self.retried:
self.retried = False
raise
self.retried = True
raise sqlalchemy.exc.DisconnectionError
config[''sqlalchemy.listeners''] = [MyListener()]
engine = engine_from_config(config, ''sqlalchemy.'')
init_model(engine)
Esta vez pude probarlo (en Pylons 1.0 + SQLAlchemy 0.6.1) y funciona. :)