Подтвердить что ты не робот

Предельное переполнение лимита Sql Alchemy QueuePool

У меня есть приложение Sql Alchemy, которое возвращает TimeOut:

TimeoutError: предел QueuePool для переполнения 5-го уровня 10, время ожидания подключения, тайм-аут 30

Я читал в другой записи, что это происходит, когда я не закрываю сессию, но я не знаю, относится ли это к моему коду:

Я подключаюсь к базе данных в 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

Затем в другом файле python я собираю некоторые данные в двух функциях, но используя DBSession, которые я инициализировал в 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()

Переменные сеанса создаются следующим образом:

#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()))

Поскольку сеанс создается в init.py, и в следующем коде я просто использую его; в какой момент мне нужно закрыть сеанс? Или что еще мне нужно сделать, чтобы управлять размером пула?

4b9b3361

Ответ 1

Вы можете управлять размером пула, добавляя параметры pool_size и max_overflow в функции create_engine

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

Ссылка здесь

Вам не нужно закрывать сеанс, но соединение должно быть закрыто после завершения транзакции. Заменить:

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

По:

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

Ссылка здесь

Также обратите внимание, что соединение mysql, которое было устарело, закрывается по истечении определенного периода времени (этот период может быть настроен в MySQL, я не помню значение по умолчанию), поэтому вам нужно передать значение pool_recycle в ваше создание механизма

Ответ 2

Добавьте следующий метод в ваш код. Он автоматически закроет все неиспользуемые/зависшие соединения и предотвратит узкие места в вашем коде. Особенно, если вы используете следующий синтаксис Model.query.filter_by (attribute = var).first() и отношения/отложенная загрузка.

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

Документация по этому вопросу доступна здесь: http://flask.pocoo.org/docs/1.0/appcontext/