python sqlalchemy + postgresql程序冻结

Bog*_*dan 23 python sqlalchemy

我遇到了一个奇怪的情况.我正在为我的程序编写一些测试用例.根据喜好,该程序可编写为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) 
Run Code Online (Sandbox Code Playgroud)

在setUp我删除任何存在的文件夹(由一些测试创建)然后我重置我的数据库(基本上删除表级联)然后我再次初始化数据库并创建一些将用于测试的服务.

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()
Run Code Online (Sandbox Code Playgroud)

除了创建服务之外,拆除做同样的事情,因为这个测试模块是与其他模块相同的套件的一部分,我不希望某些测试留下一些东西.

现在我用sqllite测试了所有测试.使用postgresql我遇到了一个非常奇怪的情况:在执行中的某个时刻,实际上不同于运行到一小部分运行(一个或两个额外的调用),程序就停止了.我的意思是没有生成错误,没有抛出异常,程序就停止了.

现在我唯一可以想到的是,不知怎的,我忘记了在某个地方打开的连接,在我超时之后发生了一些事情.但是我有很多联系,所以在我开始讨论所有代码之前,我会很感激一些建议/意见.

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

此致,波格丹

zzz*_*eek 31

基于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测试套件运行其3​​000次测试时,我们确保我们完全控制连接,并且通常一次只打开一个连接(仍然,在Pypy上运行有一些行为仍会导致PG挂起..这很难).有一个称为AssertionPool可以使用的池类,它确保一次只检出一个连接,否则会引发信息错误(显示检出的位置).

  • MySQL也有同样的问题。我要做的就是`db.session.close_all()`,一切正常。 (2认同)

kro*_*ens 12

我发现这个问题的一个解决方案是db.session.close()在任何试图打电话之前打电话db.drop_all().这将在删除表之前关闭连接,从而阻止Postgres锁定表.

请在此处查看有关此问题的更深入的讨论.