Django select_for_update在芹菜任务和竞争条件下并且是唯一的

时间:2014-04-09 23:08:28

标签: django celery django-celery

该应用程序具有这些相关模型,公司,节点和日志。

class VCompany(models.Model):
    company_name = models.CharField(max_length=50,  ...)

class VNode(models.Model):
            company = models.ForeignKey(VCompany, ...)
            name1 = models.CharField(...)
            name2 = models.CharField(...)

class Log(models.Model):
    node = models.ForeignKey(VNode, ... )

VNode必须是唯一的。不幸的是,没有简单的独特/独特在一起。如果name1已知,则company和name1的组合是唯一的。如果name2已知,则company和name2的组合是唯一的。 name1或name2或两者都是已知的。

问题1:是否可以为上述案例构建一个独特的条款?怎么样?

芹菜任务用于通过处理文件中的某些数据在日志中创建记录。有许多芹菜任务同时运行以创建日志记录。创建日志记录时,可能需要创建vnode。这会导致创建重复的vnode记录。为了解决这个问题,我正在这样做:

with transaction.atomic():
    # Get the company for update as a sync method.
    company = VCompany.objects.select_for_update().get(company_name=company)
    if name1:
        node, create = VNode.objects.get_or_create(company=company, name1=... )
        ... set other node data ...
        node.save()
        return node
    if name2:
        node, create = VNode.objects.get_or_create(company=company, name2=... )
        ... set other node data ...
        node.save()
        return node

此代码显然有效。但是,如果我删除with transaction.atomic(),它会可靠地失败。

问题2:为什么需要transaction.atomic()?需要吗?

问题3:django的ORM什么时候发布select_for_update? get_or_create是否会在创建新节点之前释放它以便发生竞争条件?

感谢您提供任何线索!

1 个答案:

答案 0 :(得分:1)

问题1:我不知道

问题2:

需要transaction_atomic,因为select_for_update仅在当前事务的持续时间内持有锁。否则,(如果您没有进行任何其他交易),它将立即释放锁定。

问题3:

当前事务关闭(提交或回滚)时释放锁。

get_or_create不是原子的,只有在db具有正确的唯一性约束时才是线程安全的。如果get_or_create违反唯一性约束,则会引发IntegrityError。

在您的情况下,锁定VCompany应该使VNode上的get_or_create方法无法失败。但是,只有在尝试创建VNode对象的任何位置正确锁定时才会出现这种情况。