программа python sqlalchemy + postgresql зависает - PullRequest
22 голосов
/ 21 июля 2011

Я столкнулся со странной ситуацией. Я пишу несколько тестов для моей программы. Программа написана для работы на sqllite или postgresqul в зависимости от предпочтений. Сейчас я пишу свой тестовый код, используя unittest. Очень в основном то, что я делаю:

def setUp(self):
    """
        Reset the database before each test.
    """
    if os.path.exists(root_storage):
        shutil.rmtree(root_storage)
    reset_database()
    initialize_startup()
    self.project_service = ProjectService()
    self.structure_helper = FilesHelper()
    user = model.User("test_user", "test_pass", "test_mail@tvb.org",
                       True, "user")
    self.test_user = dao.store_entity(user) 

В настройках я удаляю все существующие папки (созданные некоторыми тестами), затем сбрасываю свою базу данных (в основном каскад сбрасываемых таблиц), затем снова инициализирую базу данных и создаю некоторые службы, которые будут использоваться для тестирования.

def tearDown(self):
    """
        Remove project folders and clean up database.
    """
    created_projects = dao.get_projects_for_user(self.test_user.id)
    for project in created_projects:
        self.structure_helper.remove_project_structure(project.name)
    reset_database()

Tear down делает то же самое, кроме создания сервисов, потому что этот тестовый модуль является частью того же пакета с другими модулями, и я не хочу, чтобы некоторые тесты оставляли после себя вещи.

Теперь все мои тесты работают нормально с sqllite. С postgresql я сталкиваюсь с очень странной ситуацией: в какой-то момент выполнения, который фактически отличается от запуска к запуску с небольшим запасом (например, один или два дополнительных вызова), программа просто останавливается. Я имею в виду, что ошибка не генерируется, исключение не выдается, программа просто останавливается.

Теперь единственное, о чем я могу думать, так это о том, что каким-то образом я забываю, что где-то открылось соединение, и после того, как оно истекло, и что-то происходит. Но у меня МНОГО соединений, поэтому прежде чем я начну изучать весь этот код, я был бы признателен за некоторые предложения / мнения.

Что может быть причиной такого поведения? С чего начать искать?

С уважением, Богдан

Ответы [ 2 ]

30 голосов
/ 25 июля 2011

Приложения на основе PostgreSQL зависают, потому что PG довольно агрессивно блокирует таблицы, в частности это не позволит команде DROP продолжаться, если какие-либо соединения открыты в ожидающей транзакции, которая каким-либо образом получила доступ к этой таблице (включая SELECT).

Если вы работаете в системе Unix, команда "ps -ef | grep 'post'" покажет вам все процессы Postgresql и вы увидите состояние текущих команд, включая зависшую "DROP TABLE" или что бы это ни было, это замерзает. Вы также можете увидеть это, если выберете в представлении pg_stat_activity.

Таким образом, ключ заключается в том, чтобы гарантировать, что не осталось никаких ожидающих транзакций - это означает, что на уровне DBAPI все результирующие курсоры закрыты, и любое открытое в настоящее время соединение имеет rollback(), вызываемое на нем, или иное явно закрытое. В SQLAlchemy это означает, что любые результирующие наборы (то есть ResultProxy) с ожидающими строками полностью исчерпаны, а любые Connection объекты были close() d, что возвращает их в пул и вызывает rollback() для базового соединения DBAPI. вам нужно убедиться, что существует какой-то безусловный код разрыва, который гарантирует, что это произойдет до того, как будет выпущена команда любого типа DROP TABLE.

Что касается "У меня МНОГО соединений", вы должны взять это под контроль. Когда набор тестов SQLA проходит через 3000 тестов что-то, мы гарантируем, что мы полностью контролируем соединения, и обычно только одно соединение открывается одновременно (тем не менее, работа на Pypy имеет некоторые поведения, которые все еще причина зависает с PG .. это жестко). Существует класс пула AssertionPool, который вы можете использовать для этого, который гарантирует, что за раз проверяется только одно соединение, в противном случае возникает информационная ошибка (показывает, где оно было проверено).

12 голосов
/ 30 июля 2014

Одно решение, которое я нашел для этой проблемы, состояло в том, чтобы позвонить db.session.close() перед любой попыткой вызвать db.drop_all().Это закроет соединение перед удалением таблиц, и Postgres не сможет заблокировать таблицы.

Более подробное обсуждение проблемы здесь .

.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...