mysql error-handling sqlalchemy pylons

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. :)