Pregunta Evitar que "el servidor MySQL se haya ido" en el servidor Python / Flask utilizado con poca frecuencia con SQLAlchemy


¿Cómo se puede configurar Flask / SQLAlchemy para crear una nueva conexión a la base de datos si no hay una?

Tengo un servidor de Python / Flask visitado con poca frecuencia que usa SQLAlchemy. Se visita cada dos días, y en la primera visita a menudo arroja un error de "servidor MySQL se ha ido". Las siguientes vistas de página están bien, pero parece poco profesional tener este error inicial.

Me gustaría saber la forma correcta de manejar esto: consejos como "hacer un tiempo de espera realmente largo", que sería de unos 4 días en este caso, no parecen correctos. ¿Cómo puedo probar la falta de una conexión de base de datos y crear una si es necesario?


37
2018-06-24 17:34


origen


Respuestas:


He tenido problemas con esto antes, y descubrí que la forma de manejarlo es no mantener las sesiones alrededor. El problema es que estás tratando de mantener una conexión abierta por mucho tiempo. En su lugar, use una sesión de ámbito local de subprocesos como tal, ya sea en __init__.py o en un paquete de utilidad que importa en todas partes:

from sqlalchemy.orm import scoped_session, sessionmaker
Session = scoped_session( sessionmaker() )

Luego configura tus motores y metadatos una vez. Esto le permite saltear las mecánicas de configuración cada vez que se conecta / desconecta. Después de eso, puede hacer su trabajo de DB así:

session = Session()
someObject = session.query( someMappedClass ).get( someId )
# use session like normal ...
session.close()

Si usted quiere aferrarse a los objetos antiguos y no quiere salir de su sesión abierta, entonces se puede utilizar el patrón de arriba y reutilizar objetos antiguos como este:

session = Session()
someObject = session.merge( someObject )
# more db stuff
session.close()

El punto es que desea abrir su sesión, hacer su trabajo y luego cerrar su sesión. Esto evita tiempos de espera muy bien. Hay muchas opciones para .merge y .add que le permiten incluir los cambios que ha realizado en objetos separados o cargar datos nuevos desde el archivo db. Los documentos son muy detallados, pero una vez que sabes lo que estás buscando, puede ser un poco más fácil de encontrar.

Para llegar hasta allí y evitar que MySQL "se vaya", debe resolver el problema de su grupo de conexiones manteniendo las conexiones abiertas por mucho tiempo y revisando una conexión anterior por usted.

Para obtener una conexión nueva, puede configurar el pool_recycle opción en su create_engine llamada. Establecer esto pool_recycle a la cantidad de segundos en el grupo de conexiones entre los registros que desea que se cree una conexión nueva en lugar de una conexión existente para que se devuelva.


42
2018-06-24 20:13



Tuve un problema similar, pero para mí obtendría el error "MySQL se ha ido" en algún momento entre 5 minutos y 2 horas de cada sesión.

Estoy usando Flask-SQLAlchemy por lo que se supone que cierra las conexiones inactivas, pero no parecía estar haciendo eso a menos que la conexión hubiera estado inactiva durante un par de horas.

Finalmente lo reduje a la siguiente configuración de Flask-SQLAlchemy:

app.config['SQLALCHEMY_POOL_SIZE'] = 100
app.config['SQLALCHEMY_POOL_RECYCLE'] = 280

La configuración predeterminada para estos son 10 y 7200 (2 horas) respectivamente.

Es una cuestión de jugar con estos ajustes para adaptarse a su entorno.

Por ejemplo, había leído en muchos lugares que SQLALCHEMY_POOL_RECYCLE debería establecerse en 3600, pero eso no funcionó para mí. Estoy alojado en PythonAnywhere y matan conexiones inactivas de MySQL después de 5 minutos (300 segundos). Así que establecer mi valor a menos de 300 resolvió el problema.

Espero que esto ayude a los demás, porque desperdicié MUCHO tiempo en este tema.

http://flask-sqlalchemy.pocoo.org/2.1/config/#configuration-keys


17
2018-03-05 21:00



2018 respuesta:  En SQLAlchemy v1.2.0 +, tienes el grupo de conexión pre-ping característica disponible para abordar este problema de "servidor MySQL se ha ido".

Pre-ping del grupo de conexión: el grupo de conexiones ahora incluye un   función opcional "pre ping" que pondrá a prueba la "vida" de un conjunto   conexión para cada pago de conexión, reciclaje transparente   Conexión DBAPI si la base de datos está desconectada. Esta característica   elimina la necesidad de la bandera de "reciclaje de piscina", así como el problema   de errores surgidos cuando se utiliza una conexión agrupada después de una base de datos   reiniciar.

Las pruebas pesimistas de las conexiones al momento del pago son posibles con el nuevo argumento:

engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)

11
2017-07-13 11:12



SI está usando Flask-SQLAlchemy:

Parece que hay una solución disponible: https://github.com/mitsuhiko/flask-sqlalchemy/issues/2

Lamentablemente, la instalación predeterminada (pip install flask-sqlalchemy) aún no aplica el parche correctamente, especialmente en este tema: https://github.com/e-dard/flask-sqlalchemy/commit/cf659f346e005d34257d256fa4c42889741fc31f

Obtener la última versión de github debería solucionarlo.


6
2018-01-20 11:41



Recientemente me encontré con el mismo problema y encontré este hilo a través de motores de búsqueda conocidos. Leí los documentos de Flask y SQLAlchemy sobre exactamente este tema, los seguí (creo) al pie de la letra, pero fue en vano.

Debajo hay un fragmento que ilustra mi patrón de codificación. Básicamente es esto:

  1. crear sesión como scoped_session
  2. en cada ruta: abrir, usar y cerrar una sesión ()
  3. Haz lo de teardown_appcontext (¿por qué?)

Aquí va:

from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker, scoped_session
import flask

engine = create_engine("mysql://....")
Session = scoped_session(sessionmaker(bind=engine))

app = flask.Flask(__name__)

@app.route('/')
def index():
    db = Session()
    # do stuff
    db.close()
    return flask.render_template('index.html')

@app.teardown_appcontext
def shutdown_session(exception=None):
    Session.remove()

0
2018-06-14 07:48



Cuando encontré este error estaba almacenando un LONGBLOB / LargeBinary imagen ~ 1MB de tamaño. Tuve que ajustar el max_allowed_packet configuración de configuración en MySQL.

solía mysqld --max-allowed-packet=16M


0
2018-06-25 01:00