【问题标题】:Intermittent Deadlock with Django LiveServerTestCase, Selenium, and PostgresDjango LiveServerTestCase、Selenium 和 Postgres 的间歇性死锁
【发布时间】:2014-07-13 01:47:18
【问题描述】:

在使用 LiveServerTestCase 和 Selenium 测试 Django/Postgres 应用程序时,我看到了间歇性死锁问题。 LiveServerTestCase 继承自 TransactionTestCase,因此所有数据库表在每次测试运行后都会被截断。但有时这种截断会导致死锁,因为其中一张表被未解决的 Postgres 事务锁定。我可以看到,因为此查询返回一行:

select * from pg_stat_activity 
         where datname='test' and current_query='<IDLE> in transaction';

所以我的应用程序中的某些活动必须创建一个未解决的事务。我对测试进行了梳理,以确保它们在退出之前等待任何更新完成,并确信不是这样。

查看 Postgres 日志,我经常看到这两行,没有对应的 COMMITROLLBACK

SHOW default_transaction_isolation
BEGIN

我怀疑这些是导致死锁的原因。知道什么可能会发出此 SQL 或如何禁用它吗?这是 Django 1.5。

【问题讨论】:

  • 您没有显示任何提及死锁的内容。你清楚到底什么是死锁吗(不仅仅是某些东西已经被锁定了)
  • 如果我启动两个psql 并在第一个开始事务但不锁定任何东西并检查第二个,第二个将显示第一个是“事务中的空闲”。所以在我看来,“交易中的闲置”本身并没有说太多。我会看一下pg_locks,并检查相关进程ID 是否打开了锁。应该有一个virtualxid 类型的锁,它是事务本身的锁。其他锁可能会出现问题。

标签: django postgresql selenium


【解决方案1】:

这个死锁的根本原因是 Django 1.5 的自动提交行为。默认情况下,Django 1.5 使用打开的事务运行,只有在您执行 UPDATEINSERT 时才会由 COMMIT 关闭。 “读取”操作 (SELECT) 导致我上面提到的不匹配的 BEGIN 语句。如果在测试结束TRUNCATE 之前发生SELECT,则似乎会发生死锁。为了避免死锁,测试必须在所有请求完成后才退出,即使请求不会导致数据库写入。如果 Ajax 调用在更新后异步更新页面的某些部分,这可能会很棘手。

更好的解决方案是使用 Django 1.6,其中 atomic() 是唯一(未弃用的)事务创建原语。它不会为读取操作打开事务,也不会留下悬空的BEGIN 语句。测试可以遵循“写”请求未决时不退出的常识方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-25
    • 2015-12-26
    • 2013-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-28
    • 2017-05-28
    相关资源
    最近更新 更多