web-dev-qa-db-fra.com

Sql Alchemy QueuePool dépassement de limite

J'ai une application SQL Alchemy qui renvoie TimeOut:

TimeoutError: Limite QueuePool de la taille 5 dépassant 10 atteinte, connexion expirée, délai dépassé 30

J'ai lu dans un article différent que cela se produit lorsque je ne ferme pas la session, mais je ne sais pas si cela s'applique à mon code:

Je me connecte à la base de données dans le fichier init.py:

from .dbmodels import (
    DBSession,
    Base,    

engine = create_engine("mysql://" + loadConfigVar("user") + ":" + loadConfigVar("password") + "@" + loadConfigVar("Host") + "/" + loadConfigVar("schema"))

#Sets the engine to the session and the Base model class
DBSession.configure(bind=engine)
Base.metadata.bind = engine

Puis, dans un autre fichier python, je collecte des données dans deux fonctions mais en utilisant DBSession que j'ai initialisée dans init.py:

from .dbmodels import DBSession
from .dbmodels import resourcestatsModel

def getFeaturedGroups(max = 1):

    try:
        #Get the number of download per resource
        transaction.commit()
        rescount = DBSession.connection().execute("select resource_id,count(resource_id) as total FROM resourcestats")

        #Move the data to an array
        resources = []
        data = {}
        for row in rescount:
            data["resource_id"] = row.resource_id
            data["total"] = row.total
            resources.append(data)

        #Get the list of groups
        group_list = toolkit.get_action('group_list')({}, {})
        for group in group_list:
            #Get the details of each group
            group_info = toolkit.get_action('group_show')({}, {'id': group})
            #Count the features of the group
            addFesturedCount(resources,group,group_info)

        #Order the FeaturedGroups by total
        FeaturedGroups.sort(key=lambda x: x["total"],reverse=True)

        print FeaturedGroups
        #Move the data of the group to the result array.
        result = []
        count = 0
        for group in FeaturedGroups:
            group_info = toolkit.get_action('group_show')({}, {'id': group["group_id"]})
            result.append(group_info)
            count = count +1
            if count == max:
                break

        return result
    except:
        return []


    def getResourceStats(resourceID):
        transaction.commit()
        return  DBSession.query(resourcestatsModel).filter_by(resource_id = resourceID).count()

Les variables de session sont créées comme ceci:

#Basic SQLAlchemy types
from sqlalchemy import (
    Column,
    Text,
    DateTime,
    Integer,
    ForeignKey
    )
# Use SQLAlchemy declarative type
from sqlalchemy.ext.declarative import declarative_base

#
from sqlalchemy.orm import (
    scoped_session,
    sessionmaker,
    )

#Use Zope' sqlalchemy  transaction manager
from zope.sqlalchemy import ZopeTransactionExtension

#Main plugin session
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))

Parce que la session est créée dans init.py et dans le code suivant, je l’utilise simplement; à quel moment dois-je fermer la session? Ou que dois-je faire d'autre pour gérer la taille du pool?

23
QLands

Vous pouvez gérer la taille du pool en ajoutant les paramètres pool_size et max_overflow dans la fonction create_engine.

engine = create_engine("mysql://" + loadConfigVar("user") + ":" + loadConfigVar("password") + "@" + loadConfigVar("Host") + "/" + loadConfigVar("schema"), 
                        pool_size=20, max_overflow=0)

La référence est ici

Vous n'avez pas besoin de fermer la session, mais la connexion devrait être fermée après que votre transaction ait été effectuée . Remplacer:

rescount = DBSession.connection().execute("select resource_id,count(resource_id) as total FROM resourcestats")

Par:

connection = DBSession.connection()
try:
    rescount = connection.execute("select resource_id,count(resource_id) as total FROM resourcestats")
    #do something
finally:
    connection.close()

La référence est ici

Notez également que la connexion obsolète de mysql est fermée après une période donnée (cette période peut être configurée dans MySQL, je ne me souviens pas de la valeur par défaut). Vous devez donc transmettre la valeur pool_recycle à la création de votre moteur.

23
Minh-Hung Nguyen

Ajoutez la méthode suivante à votre code. Il fermera automatiquement toutes les connexions inutilisées/suspendues et évitera les goulots d'étranglement dans votre code. Surtout si vous utilisez la syntaxe suivante Model.query.filter_by (attribut = var) .first () et le chargement des relations/lazy.

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

La documentation à ce sujet est disponible ici: http://flask.pocoo.org/docs/1.0/appcontext/

0