【问题标题】:python sqlalchemy + postgresql program freezespython sqlalchemy + postgresql程序冻结
【发布时间】:2014-07-30 11:56:45
【问题描述】:

我遇到了一个奇怪的情况。我正在为我的程序编写一些测试用例。该程序被编写为在 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 我遇到了一个非常奇怪的情况:在执行的某个时刻,实际上与运行之间的差异很小(例如一两个额外的调用),程序只是停止了。我的意思是没有产生错误,没有抛出异常,程序只是停止。

现在我唯一能想到的是,不知何故我忘记了某处打开的连接,并且在我超时并且发生了一些事情之后。但是我有很多联系,所以在我开始研究所有代码之前,我会很感激一些建议/意见。

什么可能导致这种行为?从哪里开始寻找?

问候, 波格丹

【问题讨论】:

    标签: python sqlalchemy


    【解决方案1】:

    基于 PostgreSQL 的应用程序冻结,因为 PG 相当积极地锁定表,特别是如果在挂起的事务中打开任何连接,并且以任何方式访问该表(包括 SELECT),它将不允许 DROP 命令继续。

    如果您使用的是 unix 系统,命令“ps -ef | grep 'post'”将显示所有 Postgresql 进程,您将看到当前命令的状态,包括挂起的“DROP TABLE”或不管它是什么,它都冻结了。如果您从 pg_stat_activity 视图中选择,也可以看到它。

    所以关键是确保没有待处理的事务存在——这意味着在 DBAPI 级别上,任何结果游标都已关闭,并且当前打开的任何连接都调用了rollback(),或者以其他方式显式关闭。在 SQLAlchemy 中,这意味着任何带有待处理行的结果集(即ResultProxy)都已完全耗尽,并且任何Connection 对象都已成为close()d,这会将它们返回到池并在底层DBAPI 连接上调用rollback()。您需要确保有某种无条件的拆卸代码,以确保在发出任何 DROP TABLE 类型的命令之前发生这种情况。

    就“我有很多人脉”而言,您应该控制它。当 SQLA 测试套件运行其 3000 项测试时,我们确保我们完全控制连接,并且通常一次只打开一个连接(不过,在 Pypy 上运行有一些仍然 导致 PG 挂起 .. 它很难)。有一个名为 AssertionPool 的池类,您可以使用它来确保一次只检出一个连接,否则会引发信息错误(显示它被检出的位置)。

    【讨论】:

    • 最好在文档的某处提及这一点。从 sqlite 切换到 Postgre 后遇到完全相同的问题。
    • 给你,多年来一直在那里:sqlalchemy.org/trac/wiki/…
    • "...以任何方式访问过该表(包括 SELECT)。"好吧,这挽救了我的心理健康!非常感谢!
    • 与 MySQL 有同样的问题。我所要做的就是db.session.close_all(),一切正常。
    • 在这里,zzzeek 链接到的那个wiki 只是链接另一个网站。你猜怎么着,那个网站显示......什么都没有,除了一个预发布说明。不太好。即使在每次测试运行后使用close_all(),有时您也会卡住。
    【解决方案2】:

    我发现这个问题的一个解决方案是在尝试调用db.drop_all() 之前调用db.session.close()。这将在删除表之前关闭连接,防止 Postgres 锁定表。

    查看更深入的问题讨论here

    【讨论】:

    • 这个答案提供了我的解决方案,而 zzzeek 的答案解释了原因。感谢两者。
    • 仍然冻结,尽管close_all() 用于拆除 pytest 中的固定装置,这是所有测试会话的唯一来源。因此,冻结还有其他一些部分,这并没有解决。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多