【问题标题】:Select for update statement not working when inside Celery task在 Celery 任务中选择更新语句不起作用
【发布时间】:2019-12-26 13:22:59
【问题描述】:

我正在开发一些代码,我需要在数据库中保存大量数据。响应大约需要一分钟或更长时间。所以我决定在 celery 任务中移动该代码。我有一个叫做芹菜任务的观点。 这里的问题是,如果 celery 任务仍在为数据库中的同一条记录运行,您不应该能够从该视图接收状态 200。

我使用 select_for_update 语句进行行级锁定,例如:

    site = self.get_object()

    try:
        with transaction.atomic():
            Site.objects.select_for_update(nowait=True).filter(pk=site.pk)
    except DatabaseError:
        raise ObjectLockedException

在视图中,并且:

    with transaction.atomic():
        models.Site.objects.select_for_update(nowait=True).get(pk=site_id)
        ....

在任务中。如您所见,代码是相同的。

我的预期结果是,如果 celery 任务已启动并获得具有 site_id 的特定站点的锁定但尚未完成,我应该在指定视图中捕获 DatabaseError。 情况并非如此,即使同一站点的任务仍在运行,视图中的 select_for_update 也会毫无例外地通过。

另外一个好笑的是,在serializer.save()上,在代码的第一个sn-p下面,在指定的视图中,我的代码等待任务完成处理。

我做错了吗?

【问题讨论】:

    标签: python-2.7 celery django-1.11


    【解决方案1】:

    with 块是上下文管理器。当控制流离开该块时,上下文关闭,即事务结束。您正在锁定记录,但没有对它们进行操作。

    尝试将您的更新移动到 with 块内。

    【讨论】:

    • 如果我将 serializer.save() 移动到 with 块中,任务将在 select_for_update 处抛出异常,就像我在特定行上出现死锁一样。可能这里的问题是我覆盖了 model.save() 方法,并且在那里我调用了我的任务。所以我假设任务中的 select_for_update 在 serializer.save() 完成之前被触发。
    • 即使我在serializer.save() 之后移动视图中的任务调用,视图在serializer.save() 上被阻止,而前一个任务尚未完成。对我来说真的很奇怪。
    • 我想知道您是否有在视图和任务中都运行的互斥数据库查询。如果是这种情况,您很可能最终会获得数据库锁定。
    • 它们是独家的。在视图(序列化程序)中,我只更新 Site 对象的一个​​字段。任务应使用相关对象(具有 site_id 外键的对象)填充数据库。如果任务仍在使用相关对象填充数据库,我只是希望您不能调用此视图。出于某种原因, serializer.save() 正在等待任务完成,然后再次触发任务。我现在真的很困惑
    • 我实际上只是发现了一些可行的方法,但仍然不确定发生了什么。似乎存在问题,因为我有 Site 对象的pre_save 方法。如果我将select_for_update 放入pre_save 方法中,这似乎可行。它就像pre_save 方法从视图中删除锁定。
    猜你喜欢
    • 1970-01-01
    • 2018-09-19
    • 1970-01-01
    • 2015-05-14
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多