web-dev-qa-db-fra.com

Éviter "le serveur MySQL est parti" sur un serveur Python/Flask rarement utilisé avec SQLAlchemy

Comment Flask/SQLAlchemy peut-il être configuré pour créer une nouvelle connexion à une base de données s'il n'en existe pas?

J'ai un serveur Python/Flask rarement visité qui utilise SQLAlchemy. Il est visité tous les deux jours et lors de la première visite, il génère souvent l'erreur "Le serveur MySQL est parti". Les pages vues suivantes sont acceptables, mais cette erreur initiale ne semble pas professionnelle.

J'aimerais savoir quelle est la bonne façon de gérer cela - des conseils tels que "faire un temps très long", ce qui serait environ 4 jours dans ce cas, ne semble pas correct. Comment puis-je tester l'absence de connexion à une base de données et en créer une si nécessaire?

41
Ollie Glass

J'ai déjà eu des problèmes avec ça, et j'ai découvert que la meilleure façon de gérer ça est de ne pas garder les sessions. Le problème est que vous essayez de garder une connexion ouverte trop longtemps. Au lieu de cela, utilisez une session locale de threads comme dans __init__.py ou dans un utilitaire que vous importez partout:

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

Configurez ensuite vos moteurs et métadonnées une fois. Cela vous permet d’ignorer les mécanismes de configuration chaque fois que vous vous connectez/déconnectez. Après cela, vous pouvez faire votre travail de base de données comme ceci:

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

Si vous souhaitez conserver d'anciens objets et que vous ne souhaitez pas laisser votre session ouverte, vous pouvez utiliser le modèle ci-dessus et réutiliser les anciens objets comme suit:

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

Le fait est que vous voulez ouvrir votre session, faire votre travail, puis fermer votre session. Cela évite très bien les délais d'attente. Il existe de nombreuses options pour .merge et .add qui vous permettent d'inclure les modifications apportées aux objets détachés ou de charger de nouvelles données à partir de la base de données. Les documents sont très verbeux, mais une fois que vous savez ce que vous recherchez, il peut être un peu plus facile à trouver.

Pour arriver à bout et empêcher MySQL de "s'en aller", vous devez résoudre le problème de votre pool de connexions en laissant les connexions ouvertes trop longtemps et en vérifiant une ancienne connexion pour vous. 

Pour obtenir une nouvelle connexion, vous pouvez définir l’option pool_recycle dans votre appel create_engine. Définissez ce pool_recycle sur le nombre de secondes dans le pool de connexions entre les extractions au cours desquelles vous souhaitez qu'une nouvelle connexion soit créée à la place d'une connexion existante à être renvoyée.

45
underrun

J'avais un problème similaire, mais pour moi, l'erreur «MySQL est parti» se situe entre 5 minutes et 2 heures par session. 

J'utilise Flask-SQLAlchemy, donc il est supposé fermer les connexions inactives, mais ne semble pas le faire, à moins que la connexion ne soit inactive depuis plus de deux heures.

Finalement, je l'ai réduit aux paramètres Flask-SQLAlchemy suivants:

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

Les paramètres par défaut pour ces paramètres sont 10 et 7200 (2 heures) respectivement.

Il suffit de jouer avec ces paramètres pour s’adapter à votre environnement. 

Par exemple, je lisais à de nombreux endroits que SQLALCHEMY_POOL_RECYCLE devait être défini sur 3600, mais cela ne fonctionnait pas pour moi. J'héberge avec PythonAnywhere et ils éliminent les connexions MySQL inactives après 5 minutes (300 secondes). Donc, fixer ma valeur à moins de 300 a résolu le problème. 

J'espère que cela aidera les autres, car j'ai perdu trop de temps sur cette question.

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

21
omerk

2018 réponse: Dans SQLAlchemy v1.2.0 +, vous disposez de la fonctionnalité connexion préalable au pool de connexions disponible pour résoudre ce problème de "Le serveur MySQL est parti".

Pool de connexions pré-ping - Le pool de connexions inclut maintenant un fonctionnalité optionnelle de "pré-test" qui testera la "vivacité" d'un pool connexion pour chaque vérification de connexion, en recyclant de manière transparente le fichier Connexion DBAPI si la base de données est déconnectée. Cette fonctionnalité élimine le besoin de l'indicateur "piscine recycler" ainsi que le problème d'erreurs générées lorsqu'une connexion en pool est utilisée après une base de données redémarrer.

Le test pessimiste des connexions à la caisse est possible avec le nouvel argument:

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

SI vous utilisez Flask-SQLAlchemy:

On dirait qu'un correctif est disponible: https://github.com/mitsuhiko/flask-sqlalchemy/issues/2

Malheureusement, l’installation par défaut (pip install flask-sqlalchemy) n’applique pas encore correctement le correctif, en particulier sur ce problème: https://github.com/e-dard/flask-sqlalchemy/commit/cf659f346e005d34257d256fa4c42889741fc31

Obtenir la dernière version de github devrait résoudre le problème.

6
Desmond Lua

Lorsque j'ai rencontré cette erreur, je stockais une image LONGBLOB/LargeBinary__ de 1 Mo environ. Je devais ajuster le paramètre de configuration max_allowed_packet dans MySQL. 

J'ai utilisé mysqld --max-allowed-packet=16M

1
Matt