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

Python sqlalchemy + программа postgresql зависает

Я столкнулся с странной ситуацией. Я пишу несколько тестов для своей программы. Программа написана для работы в 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", "[email protected]",
                       True, "user")
    self.test_user = dao.store_entity(user) 

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

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

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

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

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

Что может вызвать такое поведение? С чего начать?

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

4b9b3361

Ответ 1

Приложения на основе 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, который можно использовать для этого, который гарантирует, что только одно соединение когда-либо проверяется в то время, когда возникает информативная ошибка (показывает, где она была извлечена).

Ответ 2

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

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