Django ORM返回陈旧数据,可能的竞争条件

时间:2015-09-18 22:21:21

标签: django postgresql python-3.x django-models django-rest-framework

考虑一个带有单个RESTful API的Django应用程序,它创建对象(使用Django REST Framework)。作为此API的一部分,我做了一些验证以确保创建调用是幂等的,这样如果您调用创建API两次,第一次将成功,第二次将失败并显示自定义错误代码。

我有一个测试此API的方案,它以下列方式间歇性地失败:

  1. 第一次API调用,成功,返回201 - >对象已据称已创建
  2. 在响应后立即进行第二次API调用
  3. 验证逻辑调用MyModel.objects.get(some_field=some_value)以检查这是否是重复呼叫
  4. 尽管在步骤1中创建了,但未找到此类对象,因此会创建重复的对象
  5. 检查管理员/查询模型时,可以看到两个对象。
  6. 更多数据:

    • 此模型没有明确的缓存,也没有此过程中涉及的任何其他缓存。
    • 我无法在本地重现
    • 在我的部署设置中,这种可能的竞争条件的失败率约为5%。
    • 本地和部署都使用PostgreSQL。
    • 部署环境确实启用了常规缓存,但在本地启用缓存时仍然没有重新启动。

    可能导致这种竞争状况的原因是什么? Django ORM是否有任何故障模式,我可能会收到过时的数据?有什么方法可以防御性地保护验证免于获取陈旧数据吗?

2 个答案:

答案 0 :(得分:0)

看看transaction.atomic:

https://docs.djangoproject.com/en/1.8/topics/db/transactions/#django.db.transaction.atomic

这有时可以解决这个问题

答案 1 :(得分:0)

我目前提出的解决方案是基于@CraigRinger的反馈,这似乎是正确的。基本上,为了从Postgres获得一致的响应,我需要实际尝试INSERT,而不仅仅是查询数据,因为存在竞争条件。

可以在https://code.djangoproject.com/ticket/20429#comment:22

中找到对此的部分引用

最重要的是,解决方案是在模型的相关字段上添加数据库强制unique=True约束(在本例中为some_field),尝试创建对象,捕获{{1}从那里开始,我可以实现自定义错误处理并将正确的结果传播到API层。